使用C#

时间:2016-11-08 16:21:40

标签: c# c memory-management struct binary

我正在做一个项目,我需要将结构化数据写入二进制文件。首先,我需要编写一个头,然后从某处获取数据,填充结构化数据块并将其写入所述文件。我正在将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;     
    }

如果数据格式正确,则该文件将被另一个应用程序读取,该应用程序可以从二进制文件中读取。我打印出两种结构类型的大小,它们看起来很好。但是,所述应用程序无法读取输出文件。

所以我有两个问题:

  1. 我在C到C#转换中使用的数据类型和Marshals是否正确?

  2. 我使用FileStream和BinaryWriter写入二进制文件。所有数据(标题和后续数据)必须按顺序(连续)。当我动态创建和编写数据结构时,我不确定如何使用以下内容分配连续内存:

  3. 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);
    }
    

1 个答案:

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