Десериализация массива байтов
Если бы я хотел заполнить структуру из двоичного файла, я бы использовал что-то вроде этого:
using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open)))
{
myStruct.ID = br.ReadSingle();
myStruct.name = br.ReadBytes(20);
}
однако я должен прочитать весь файл в массив байтов перед десериализацией, потому что я хочу сделать некоторую предварительную обработку. Есть ли управлял способ заполнения моей структуры из массива байтов, предпочтительно аналогичного приведенному выше?
3 ответов
Это пример, чтобы взять некоторые данные (на самом деле система.Данные.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!
}
надеюсь, что это помогает. Как подразумевал Нейт, мы используем MemoryStream здесь.
посмотри метода bitconverter класса. Это может сделать то, что вам нужно.
для очень простых структур, которые не Сериализуемы и содержат только базовые типы, это работает. Я использую его для разбора файлов, которые имеют известный формат. Ошибка проверки удалена для ясности.
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;
}
}
}
структуры должны быть объявлены так (и не могут содержать массивы, я думаю, не пробовали это - endian swap, вероятно, запутается).
[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
}