web-dev-qa-db-ja.com

バイト配列の逆シリアル化

バイナリファイルから構造を埋めたい場合は、次のようなものを使用します。

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

ただし、前処理を行いたいので、逆シリアル化する前にファイル全体をバイト配列に読み込む必要があります。バイト配列から構造を埋めるmanaged方法はありますか?できれば上記と同様ですか?

13
Joulukuusi

これは、DeflateStreamを使用して圧縮しながら、一部のデータ(実際にはSystem.Data.DataSet)を取得し、バイトの配列にシリアル化するためのサンプルです。

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を使用しています。

17
Glenn Ferrie

BitConverter クラスを見てください。それはあなたが必要とすることをするかもしれません。

1
Joel Coehoorn

シリアル化できず、基本型のみを含む非常に単純な構造体の場合、これは機能します。既知の形式のファイルを解析するために使用します。わかりやすくするために、エラーチェックは削除されました。

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

構造体はこのように宣言する必要があります(そして配列を含めることはできません、私はそれを試していないと思います-エンディアンスワップはおそらく混乱するでしょう)。

[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
}
0