与C类似,我们可以使用结构指针来读取或编写结构化二进制数据,如文件头等,在C#中有类似的方法吗?
答案 0 :(得分:8)
在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
,Double
以及{ {1}},byte
以及其中的数组。直接支持char
,但仅限于
该字符串以长度为前缀,一次编码为整数7位。
如果您以这种方式从string
以这种方式编写字符串,这对我来说似乎很有用。但这很容易,比如说你的字符串以DWord长度为前缀,后跟那么多的ASCII字符:
BinaryWriter
请注意,我不将int len = (int)br.ReadUInt32();
string s = Encoding.ASCII.GetString(br.ReadBytes(len));
和BinaryReader
个对象包含在BinaryWriter
块中。这是因为,尽管它们是using()
,但它们IDisposable
所做的只是在基础流上调用Dispose()
(在这些示例中为Dispose()
)。
由于所有MemoryStream
/ BinaryReader
都是基础流周围的一组BinaryWriter
/ Read()
包装器,我不明白为什么它们是{{ 1}}无论如何。当您尝试做正确的事情并在所有Write()
上拨打IDisposable
时,这会让您感到困惑,并且您的信息流突然被丢弃。
答案 1 :(得分:2)
要从二进制文件中读取任意结构的数据(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
将结果字节数组写入文件。
答案 2 :(得分:0)
这是一个简单的例子,展示了如何以二进制格式在文件中读取和写入数据。
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();
}
}
}