2008-11-25 73 views
0

我有一個字節流,我需要解析成一個結構,我也需要能夠解析結構回字節流。解析一個字節流到一個結構/類

下面是我想要使用BitConverter解析數值的示例。我希望有一個更有效的方法來做到這一點,因爲我的結構是巨大的!

ref struct TestStruct 
{ 
    int TestInt; 
    float TestFloat; 
}; 

int main(array<System::String ^> ^args) 
{ 
    // populating array - just for demo, it's really coming from a file 
    array<unsigned char>^ arrBytes = gcnew array<unsigned char>(8); 
    Array::Copy(BitConverter::GetBytes((int)1234), arrBytes, 4); 
    Array::Copy(BitConverter::GetBytes((float)12.34), 0, arrBytes, 4, 4); 

    // parsing to struct - I want help 
    TestStruct^ myStruct = gcnew TestStruct(); 
    myStruct->TestInt = BitConverter::ToInt32(arrBytes, 0); 
    myStruct->TestFloat = BitConverter::ToSingle(arrBytes, 4); 

    String^ str = Console::ReadLine(); 
    return 0; 
} 

回答

1

對於像這樣的東西,你通常使用代碼生成器。假設來源是這樣的:

struct a { 
    int i; 
} 

struct b { 
    string name; 
    struct a a; 
} 

你要做的就是寫一個簡單的解析器,搜索信號源(可能是一些頭文件)的「結構」,那麼你讀的結構的名稱(之間的任何「struct」和「{」)。寫到輸出:

cout << "struct " << name << " * read_struct_" << name << " (stream in) {" << NL 
    << " struct " << name << " * result = malloc (sizeof(struct " << name << "));" NL 
parseFields (headerStream); 
cout << " return result;" << NL << "}" << NL ; } 

請注意我的C++有點生疏,所以這可能不會編譯,但你應該明白了。

在parseFields中,您讀取每行並將其分成兩部分:最後一個空格之前的任何內容(即第一個示例中的「int」)以及最後一個空格和「;」之間的內容。在這種情況下,這將是「我」。您現在寫入輸出:

cout << "read_" << fieldType << "(in, &result->" << fieldName << ");" << NL; 

注意:您需要使用「_」替換字段類型的所有空格。

在輸出中,這看起來像這樣:

struct a * read_struct_a (stream in) { 
    struct a * result = malloc(sizeof(struct a)); 
    read_int(in, &result->i); 
    return result; 
} 

這允許您定義如何讀取或別的地方寫一個int(公用模塊)。

現在,您的代碼可以從頭文件中讀取結構定義,並創建可從某個流中讀取結構的新代碼。重複此操作以將結構寫入流。編譯生成的代碼,你就完成了。

您還需要編寫單元測試以驗證解析是否正常工作:)只需在內存中創建一個結構,使用寫入方法將其保存在某處並再次讀取。現在這兩個結構應該是相同的。您將需要編寫第三個代碼生成器來創建代碼來比較兩個結構。

1

Here是序列化的.NET

對於通用C的解釋++(未管理),看看boost::serialize

+0

如何格式化二進制格式已經定義。這帶給我自定義序列化並帶回相同的問題。幾百行BitConverter,還是存在更好的方法? – rozon 2008-11-25 08:44:08

-1

你提到C++和.NET。類不保證存儲在一個連續的內存塊 - 僅限於C++,你應該,如果你想避免保存每個項目上單獨能夠做到的東西沿線的

char buffer[sizeof(MYSTRUCT)]; 
memcopy((char*) &mystruct, buffer, sizeof(MYSTRUCT)); 

For .net you MUST use serialization。這很煩人,但這是託管代碼的「特性」之一 - 您必須讓它爲您管理它。

-Adam

+0

是的!如果你可以解釋如何在.NET中使用託管引用類型來完成此操作。 – rozon 2008-11-25 08:45:35

+0

你不能。您必須單獨保存每個項目,或使用序列化。 – 2008-11-25 08:54:10

0

序列化是很好的,但在我的情況下,我不需要'額外',我不得不做同樣的工作來完全控制位。對於大多數,它可能是我想的解決方案。

給Digulla先生一個正確的答案,因爲它是最類似我的解決方案。還要感謝戴維斯先生,他直接告訴我必須完成的事實...

相關問題