2011-07-05 55 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 
}