Cの場合と同様に、構造ポインターを使用してファイルヘッダーなどの構造化バイナリデータを読み書きできますが、C#でこれを行う同様の方法はありますか?
3 に答える
私の意見では、aを使用することが最善の方法BinaryReader
である傾向があります。BinaryWriter
MemoryStream
バイナリデータの解析:
byte[] buf = f // some data from somewhere
using (var ms = new MemoryStream(buf, false)) { // Read-only
var br = new BinaryReader(ms);
UInt32 len = br.ReadUInt32();
// ...
}
バイナリデータの生成:
byte[] result;
using (var ms = new MemoryStream()) { // Expandable
var bw = new BinaryWriter(ms);
UInt32 len = 0x1337;
bw.Write(len);
// ...
result = ms.GetBuffer(); // Get the underlying byte array you've created.
}
これらを使用すると、、、、、およびそれらの配列など(U)Int16, 32, 64
、ほとんどSingle
のファイルヘッダーなどに必要なすべてのプリミティブ型を読み書きできます。s は直接サポートされていますが、Double
byte
char
string
文字列の前には長さがあり、一度に7ビットの整数としてエンコードされます。
これは、この方法からこの方法で文字列を記述した場合にのみ役立つようですBinaryWriter
。ただし、文字列の前にDWordの長さがあり、その後にその数のASCII文字が続くと言うのは簡単です。
int len = (int)br.ReadUInt32();
string s = Encoding.ASCII.GetString(br.ReadBytes(len));
およびオブジェクトがブロックにラップされていないことに注意してください。これは、それらがであるにもかかわらず、基礎となるストリーム(これらの例では)を呼び出すだけであるためです。 BinaryReader
BinaryWriter
using()
IDisposable
Dispose()
Dispose()
MemoryStream
すべてのBinaryReader
/ BinaryWriter
areは、基になるストリームのRead()
/Write()
ラッパーのセットであるため、とにかくなぜそれらが存在するのかわかりませIDisposable
ん。The Right Thingを実行Dispose()
してすべてIDisposable
のを呼び出しようとすると、混乱します。突然、ストリームが破棄されます。
バイナリファイルから任意に構造化されたデータ(a)を読み取るstruct
には、最初に次のものが必要です。
public static T ToStructure<T>(byte[] data)
{
unsafe
{
fixed (byte* p = &data[0])
{
return (T)Marshal.PtrToStructure(new IntPtr(p), typeof(T));
}
};
}
その後、次のことができます。
public static T Read<T>(BinaryReader reader) where T: new()
{
T instance = new T();
return ToStructure<T>(reader.ReadBytes(Marshal.SizeOf(instance)));
}
struct
書き込むには、オブジェクトをバイト配列に変換します。
public static byte[] ToByteArray(object obj)
{
int len = Marshal.SizeOf(obj);
byte[] arr = new byte[len];
IntPtr ptr = Marshal.AllocHGlobal(len);
Marshal.StructureToPtr(obj, ptr, true);
Marshal.Copy(ptr, arr, 0, len);
Marshal.FreeHGlobal(ptr);
return arr;
}
...そして、結果のバイト配列を。を使用してファイルに書き込むだけですBinaryWriter
。
これは、ファイルとの間でバイナリ形式のデータを読み書きする方法を示す簡単な例です。
using System;
using System.IO;
namespace myFileRead
{
class Program
{
static void Main(string[] args)
{
// Let's create new data file.
string myFileName = @"C:\Integers.dat";
//check if already exists
if (File.Exists(myFileName))
{
Console.WriteLine(myFileName + " already exists in the selected directory.");
return;
}
FileStream fs = new FileStream(myFileName, FileMode.CreateNew);
// Instantialte a Binary writer to write data
BinaryWriter bw = new BinaryWriter(fs);
// write some data with bw
for (int i = 0; i < 100; i++)
{
bw.Write((int)i);
}
bw.Close();
fs.Close();
// Instantiate a reader to read content from file
fs = new FileStream(myFileName, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
// Read data from the file
for (int i = 0; i < 100; i++)
{
//read data as Int32
Console.WriteLine(br.ReadInt32());
}
//close the file
br.Close();
fs.Close();
}
}
}