2011-07-05 52 views
11

如果我想填補一個二進制文件的結構,我會用這樣的:反序列化的字節數組

using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open))) 
{ 
    myStruct.ID = br.ReadSingle(); 
    myStruct.name = br.ReadBytes(20); 
} 

不過,我必須反序列化之前讀取整個文件轉換成字節數組,因爲我想做一些預處理。有沒有任何管理方式來填補我的結構從字節數組,最好是類似於上面的?

+2

'MemoryStream'? – Nate

+4

你應該考慮讓你的類型可序列化。如果這是你感興趣的東西,我會提供一個樣本。有關二進制序列化,請參閱「BinaryFormatter」。 –

+0

@Nate,謝謝,它似乎使用'MemoryStream'是一個好主意! @GlennFerrieLive,我以前從來沒有使用過'BinaryFormatter',但是通過一些例子來判斷它看起來像是「爲我鑄造一個結構體」。即使是一個小樣本,我也會很感激。謝謝! – Joulukuusi

回答

16

這是一個取樣一些數據(實際上是一個System.Data.DataSet)並序列化爲一個字節數組的示例,同時使用DeflateStream進行壓縮。

try 
{ 
    var formatter = new BinaryFormatter(); 
    byte[] content; 
    using (var ms = new MemoryStream()) 
    { 
     using (var ds = new DeflateStream(ms, CompressionMode.Compress, true)) 
     { 
      formatter.Serialize(ds, set); 
     } 
     ms.Position = 0; 
     content = ms.GetBuffer(); 
     contentAsString = BytesToString(content); 
    } 
} 
catch (Exception ex) { /* handle exception omitted */ } 

這裏是相反的代碼進行反序列化:

 var set = new DataSet(); 
     try 
     { 
      var content = StringToBytes(s); 
      var formatter = new BinaryFormatter(); 
      using (var ms = new MemoryStream(content)) 
      { 
       using (var ds = new DeflateStream(ms, CompressionMode.Decompress, true)) 
       { 
        set = (DataSet)formatter.Deserialize(ds);       
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      // removed error handling logic! 
     } 

希望這有助於。正如Nate暗示的,我們在這裏使用MemoryStream。

+0

非常感謝,這應該對大型建築更有幫助。只是一個問題 - 改變結構對齊會影響反序列化結果嗎? – Joulukuusi

+0

我認爲結構對齊會影響序列化和反序列化,但我不確定。 –

+1

對於投擲壓縮+1,僅僅因爲你可以用 –

1

看一看BitConverter這個課。這可能會做你需要的。

+0

感謝您的回答,那個班級確實做到了我需要的東西。唯一的小麻煩是我需要手動跟蹤位置。 – Joulukuusi

0

對於不是可串行化且僅包含基本類型的非常簡單的結構體,這可行。我用它來解析具有已知格式的文件。清除錯誤檢查已刪除。

using System; 
using System.IO; 
using System.Reflection; 
using System.Runtime.InteropServices; 

namespace FontUtil 
{ 
    public static class Reader 
    { 
     public static T Read<T>(BinaryReader reader, bool fileIsLittleEndian = false) 
     { 
      Type type = typeof(T); 
      int size = Marshal.SizeOf(type); 
      byte[] buffer = new byte[size]; 
      reader.Read(buffer, 0, size); 
      if (BitConverter.IsLittleEndian != fileIsLittleEndian) 
      { 
       FieldInfo[] fields = type.GetFields(); 
       foreach (FieldInfo field in fields) 
       { 
        int offset = (int)Marshal.OffsetOf(type, field.Name); 
        int fieldSize = Marshal.SizeOf(field.FieldType); 
        for (int b = offset, t = fieldSize + b - 1; b < t; ++b, --t) 
        { 
         byte temp = buffer[t]; 
         buffer[t] = buffer[b]; 
         buffer[b] = temp; 
        } 
       } 
      } 
      GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); 
      T obj = (T)Marshal.PtrToStructure(h.AddrOfPinnedObject(), type); 
      h.Free(); 
      return obj; 
     } 
    } 
} 

的Structs需要聲明是這樣的(並且不能包含數組,我認爲,並沒有說出來 - 字節序交換可能會感到困惑)。

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct NameRecord 
{ 
    public UInt16 uPlatformID; 
    public UInt16 uEncodingID; 
    public UInt16 uLanguageID; 
    public UInt16 uNameID; 
    public UInt16 uStringLength; 
    public UInt16 uStringOffset; //from start of storage area 
}