2009-12-11 74 views
2

我被困在這一個。使用MarshalAs和StructLayout讀取二進制數據

我讀它具有TE以下格式的二進制文件:

Field name Size in bytes  Example 
------------------------------------- 
Date  19    1998_12_22 PM 20:15 
Serial  4     0001 

使用下面的結構和使用的答案this question我試圖讀取文件。

[StructLayout(LayoutKind.Explicit, Size=23, Pack = 1)] 
struct MeasurementStruct 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)] 
    [FieldOffset(0)] 
    public string Date; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] 
    [FieldOffset(19)] 
    public string Serial; 
} 

然而,實例保存這個結構我在FieldOffset得到一個錯誤的類時19遺憾的是,這個錯誤是在荷蘭,但它大致翻譯爲「無法加載MeasurementStruct因爲現場在關19未對齊好(字段可能重疊)「。

我發現將FieldOffset [19]更改爲FieldOffset [20]會使錯誤消失。但是,在我的情況下,20是不是正確的抵消,是嗎?

回答

1

看起來你的數據(23字節)和結構的大小(24字節)之間存在大小問題。這是正常的嗎?

更新:Pack = 1屬性應該保證內存對齊,但Google搜索會在結構的字段對齊 上提供不同的響應。 你可以做的是一個字節數組來讀取23個字節,然後抽取兩個字符串Encoding類:

byte[] array = ... // read 23 bytes 
String s1 = Encoding.ASCII.GetString(array, 0, 19); 
String s2 = Encoding.ASCII.GetString(array, 19, 4); 
+0

這是一個錯字!修復.. – 2009-12-11 12:01:36

+0

感謝您的回答。我給出的結構只是文件格式的簡化版本。實際的格式更加龐大和複雜,因此編碼所有字段並不是真正的選擇 – 2009-12-11 13:10:19

0

20可能是正確的這一架構所抵消。編譯器將填充零以便將結構成員放在甚至是位置上。確切地說,體系結構和編譯器依賴程度如何,但如果我沒有弄錯的話,它必須是32位體系結構中的4的倍數。

例如,下面的結構:

struct MyStruct 
{ 
    char ch; // Offset 0 
      // 3 "invisible" bytes padding inserted by the compiler 
    int i; // Offset 4 
} 
0

可能是string要求每個字符的2字節(Unicode)的,讀作一個字節數組,並使用ASCIIEncoding轉換爲字符串的

0

無回答我正在尋找什麼,但是我通過定義下面的結構來找到更好的方法。

[StructLayout(LayoutKind.Sequential, Size = MeasurementStructSize, Pack = 1)] 
struct MeasurementStruct 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 19)] 
    public string Date; 

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)] 
    public string SerialNumber; 

} 

我將LayoutKind更改爲Sequential。在這種情況下,Pack字段實際上有一個含義,我不需要添加FieldOffset。上述工作正常。

無論如何感謝你們所有人!