我正在做一个项目,我需要将结构化数据写入二进制文件。首先,我需要编写一个头,然后从某处获取数据,填充结构化数据块并将其写入所述文件。我正在将C结构移植到C#,如下所示:
C header struct:
typedef struct
{
DWORD uSignature;
DWORD uRecordLength;
} Header;
C数据结构:
typedef struct
{
DWORD uCode; // a two character identifier
char uLabel[10];
int uDate;
float uData[37];
} MyData;
这是C#header struct:
struct Header
{
public uint uSignature;
public uint uRecordLength;
}
这里是C#数据结构:
struct MyData
{
public MyData (int Count) : this ()
{
uData = new Single[Count];
}
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] uCode;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] uLabel;
public int uDate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 37)]
public Single [] uData;
}
如果数据格式正确,则该文件将被另一个应用程序读取,该应用程序可以从二进制文件中读取。我打印出两种结构类型的大小,它们看起来很好。但是,所述应用程序无法读取输出文件。
所以我有两个问题:
我在C到C#转换中使用的数据类型和Marshals是否正确?
我使用FileStream和BinaryWriter写入二进制文件。所有数据(标题和后续数据)必须按顺序(连续)。当我动态创建和编写数据结构时,我不确定如何使用以下内容分配连续内存:
public static byte[] GetData(object obj)
{
var size = Marshal.SizeOf(obj.GetType());
var data = new byte[size];
IntPtr pnt = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(obj, pnt, true);
// Copy the array to unmanaged memory.
Marshal.Copy(pnt, data, 0, size);
return data;
}
finally
{
// Free the unmanaged memory.
Marshal.FreeHGlobal(pnt);
}
}
非常感谢任何帮助!
[编辑] 我添加了两种方法将特定的struct数据转换为字节数组,但该文件仍然不可读:
private byte[] DataToByteArray(MyData data)
{
int len = 0;
var size = Marshal.SizeOf(data.GetType());
var barray = new byte[size];
data.uCode.CopyTo(barray, 0);
len += data.uCode.Length;
data.uLabel.CopyTo(barray, len);
len += data.uLabel.Length;
BitConverter.GetBytes(0).CopyTo(barray, len);
len += data.uData.Length;
Buffer.BlockCopy(data.uData, 0, barray, len, data.uData.Length);
return barray;
}
private byte[] HeadToByteArray(Header data)
{
var size = Marshal.SizeOf(data.GetType());
var barray = new byte[size];
BitConverter.GetBytes(data.uSignature).CopyTo(barray, 0);
BitConverter.GetBytes(data.uRecordLength).CopyTo(barray, 4);
return barray;
}
【EDIT2】 以下是它在C中的工作原理:
#define NQ_EX 'QN'
FILE *fout;
fopen_s(&fout, "path_to_the_file", "wb");
Header head = { val1, sizeof(MyData) };
fwrite(&head, sizeof(Header), 1, fout);
while (!stop && data_is_coming)
{
MyData data;
memset(&data, 0, sizeof(data));
data.uCode = NQ_EX;
sprintf_s(data.uLabel, "%s", getVal("field1"));
data.uData[0] = getVal("field2");
data.uData[1] = getVal("field3");
....
fwrite(&data, sizeof(MyData), 1, fout);
}
答案 0 :(得分:0)
字节顺序似乎很好。在Jeroen和其他人的帮助下进行一些更改和测试之后,我能够使它工作。问题是由于Block.copy方法造成的。我将它更改为Array.copy,如下所示:
private byte[] DataToByteArray(MyData data)
{
int len = 0;
var size = Marshal.SizeOf(data.GetType());
var barray = new byte[size];
data.uCode.CopyTo(barray, 0);
len += data.uCode.Length;
data.uLabel.CopyTo(barray, len);
len += data.uLabel.Length;
BitConverter.GetBytes(0).CopyTo(barray, len);
len += data.uData.Length;
for (int i = 0; i < data.uData.Length; i++)
Array.Copy(BitConverter.GetBytes(data.uData[i]), 0, barray, len+i * 4, 4);
return barray;
}