2011-07-05 21 views
11

Si quería llenar una estructura de un archivo binario, me gustaría utilizar algo como esto:deserializar una matriz de bytes

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

Sin embargo, debo leer todo el archivo en una matriz de bytes antes de deserializar, porque quiero hacer un preprocesamiento ¿Hay alguna forma gestionada para completar mi estructura desde la matriz de bytes, preferiblemente similar a la anterior?

+2

'MemoryStream'? – Nate

+4

Debería considerar hacer que su tipo sea serializable. Si eso es algo que le interesa, proporcionaré una muestra. Consulte "BinaryFormatter" para la serialización binaria. –

+0

@Nate, gracias, parece que usar 'MemoryStream' es una buena idea! @GlennFerrieLive, nunca he trabajado con 'BinaryFormatter' antes, pero a juzgar por algunos ejemplos, me parece que se trata de" casting a struct ". Realmente apreciaré incluso una pequeña muestra. ¡Gracias! – Joulukuusi

Respuesta

16

Este es un ejemplo para tomar algunos datos (en realidad, un System.Data.DataSet) y serializarlos en una matriz de bytes, mientras se comprime usando 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 */ } 

Este es el código a la inversa para deserializar:

 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! 
     } 

Espero que esto ayude. Como Nate dio a entender, estamos usando MemoryStream aquí.

+0

Muchas gracias, esto debería ser más útil con las grandes estructuras. Solo una pregunta: ¿el cambio de las alineaciones de la estructura afecta el resultado de la deserialización? – Joulukuusi

+0

Creo que la alineación de la estructura afecta la serialización y la deserialización, pero no estoy seguro. –

+1

+1 para tirar en compresión, solo porque puede –

1

Echa un vistazo a la clase BitConverter. Eso podría hacer lo que necesites.

+0

Gracias por la respuesta, esa clase realmente hace lo que necesito. El único inconveniente es que necesito seguir la posición manualmente. – Joulukuusi

0

Para estructuras muy simples que no son serializables y contienen solo tipos de base, esto funciona. Lo uso para analizar archivos que tienen un formato conocido. Se eliminó la comprobación de errores para mayor claridad.

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; 
     } 
    } 
} 

Las estructuras deben ser declarados como esto (y no puede contener matrices, creo, no han intentado que fuera - el canje endian probablemente se confunden).

[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 
} 
Cuestiones relacionadas