データがどのようにシリアル化されたかわかりません (プロトコルもデータの説明も指定していません)。ただし、他の質問の解決策を詳しく説明することで問題が解決するとおっしゃいました。そのための詳細を説明します。次の例で行ったように、バイナリストリームを使用する代わりに、データがフォーマットに従って解析されるように実装を変更するのは簡単です。
あなたが言及している質問では、解決策を得るために独自の属性を実装することを提案していたと思います。
ここで実装の例を挙げることができます(これは単なる例です。本番環境で使用する前に編集してください...):
データ構造を含むファイル:
//MyData.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FixedLengthFileReader
{
class MyData
{
[Layout(0, 10)]
public string field1;
[Layout(10, 4)]
public int field2;
[Layout(14, 8)]
public double field3;
public override String ToString() {
return String.Format("String: {0}; int: {1}; double: {2}", field1, field2, field3);
}
}
}
属性:
// LayoutAttribute.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FixedLengthFileReader
{
[AttributeUsage(AttributeTargets.Field)]
class LayoutAttribute : Attribute
{
private int _index;
private int _length;
public int index
{
get { return _index; }
}
public int length
{
get { return _length; }
}
public LayoutAttribute(int index, int length)
{
this._index = index;
this._length = length;
}
}
}
リーダーの実装例:
//FixedLengthReader.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
namespace FixedLengthFileReader
{
class FixedLengthReader
{
private Stream stream;
private byte[] buffer;
public FixedLengthReader(Stream stream)
{
this.stream = stream;
this.buffer = new byte[4];
}
public void read<T>(T data)
{
foreach (FieldInfo fi in typeof(T).GetFields())
{
foreach (object attr in fi.GetCustomAttributes())
{
if (attr is LayoutAttribute)
{
LayoutAttribute la = (LayoutAttribute)attr;
stream.Seek(la.index, SeekOrigin.Begin);
if (buffer.Length < la.length) buffer = new byte[la.length];
stream.Read(buffer, 0, la.length);
if (fi.FieldType.Equals(typeof(int)))
{
fi.SetValue(data, BitConverter.ToInt32(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(bool)))
{
fi.SetValue(data, BitConverter.ToBoolean(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(string)))
{
// --- If string was written using UTF8 ---
byte[] tmp = new byte[la.length];
Array.Copy(buffer, tmp, tmp.Length);
fi.SetValue(data, System.Text.Encoding.UTF8.GetString(tmp));
// --- ALTERNATIVE: Chars were written to file ---
//char[] tmp = new char[la.length - 1];
//for (int i = 0; i < la.length; i++)
//{
// tmp[i] = BitConverter.ToChar(buffer, i * sizeof(char));
//}
//fi.SetValue(data, new string(tmp));
}
else if (fi.FieldType.Equals(typeof(double)))
{
fi.SetValue(data, BitConverter.ToDouble(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(short)))
{
fi.SetValue(data, BitConverter.ToInt16(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(long)))
{
fi.SetValue(data, BitConverter.ToInt64(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(float)))
{
fi.SetValue(data, BitConverter.ToSingle(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(ushort)))
{
fi.SetValue(data, BitConverter.ToUInt16(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(uint)))
{
fi.SetValue(data, BitConverter.ToUInt32(buffer, 0));
}
else if (fi.FieldType.Equals(typeof(ulong)))
{
fi.SetValue(data, BitConverter.ToUInt64(buffer, 0));
}
}
}
}
}
}
}
最後に、プログラムの実装例 (非常に単純):
// Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace FixedLengthFileReader
{
class Program
{
static void Main(string[] args)
{
MyData md = new MyData();
Console.WriteLine(md);
Stream s = File.OpenRead("testFile.bin");
FixedLengthReader flr = new FixedLengthReader(s);
flr.read(md);
s.Close();
Console.WriteLine(md);
}
}
}
サンプル バイナリ ファイルに対してそのコードをテストする場合は、次の 16 進コードでファイルを作成できます。
41 42 43 44 45 46 47 48 49 4A 01 00 00 00 00 00 00
00 00 00 E0 3F
次のバイトを表します。
- 文字列 ABCDEFGHIJ (10 バイト)
- 整数 1 (4 バイト)
- double 0.5 (8 バイト)
(XVI32を使用してファイルを作成し、その16進コードを追加してtestFile.binとして保存しました)