【问题标题】:Writing bytes from a struct into a file with c#使用c#将结构中的字节写入文件
【发布时间】:2013-06-27 08:43:15
【问题描述】:

大家早上好!

我在这里遇到了一个新问题。我必须写下来自我在系统中声明的结构的数据。

我创建的结构只有两个字段,我用来稍后将其转换为字节。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct MyStructData
{
    public short Id;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string Name;
}

我使用以下代码将此结构转换为字节:

private byte[] getBytes(MyStructData aux)
{
    int length = Marshal.SizeOf(aux);
    IntPtr ptr = Marshal.AllocHGlobal(length);
    byte[] myBuffer = new byte[length];

    Marshal.StructureToPtr(aux, ptr, true);
    Marshal.Copy(ptr, myBuffer, 0, length);
    Marshal.FreeHGlobal(ptr);

    return myBuffer;
}

这个函数用于转换 MyStructData 类型元素的 List 结构中的每个元素,其中我有我想要发送到另一台机器的所有寄存器,我使用下面粘贴的代码来完成:

string saveToFilePath = "D:\\" + filename;
Stream myStream = myFtpRequest.GetRequestStream();

using (FileStream myFileStream = new FileStream(saveToFilePath, FileMode.Create))
{
    foreach (MyStructData myData in myStructDataList)
    {
        int length = 2048;
        byte[] newBuffer = new byte[length];
        newBuffer = getBytes(myCust);

        int len = 0;
        int bytesRead = 0;

        myFileStream.Write(newBuffer, 0, len);
        bytesRead += len;
    }

    myFileStream.Close();
}

我的问题是我看到我的新文件是空的,我不明白为什么它没有得到我的字节信息。我已经检查了列表是否带有数据,并且我还检查了我的字节转换功能是否也能正常工作,但我无法直截了当地查看导致我的文件为空的原因。

如果有人知道隧道尽头的光明,我将非常感谢您的帮助!

编辑现在我有另一种方法可以将数据写入文件并且效果很好:

using (Stream stream = new FileStream(saveToFilePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
    using (BinaryWriter writer = new BinaryWriter(stream, Encoding.Default))
    {
        // get all data
        foreach (MyStructData myData in myStructDataList)
        {
            byte[] newBuffer = getBytes(cd);
            writer.Write(newBuffer);
        }
    }
}

【问题讨论】:

    标签: c# struct byte filestream


    【解决方案1】:

    FileStream.Write 的第三个参数是要写入 的字节数。它不应该是 0。

    string saveToFilePath = "D:\\" + filename;
    Stream myStream = myFtpRequest.GetRequestStream();
    
    int bytesWritten = 0;
    using (FileStream myFileStream = new FileStream(saveToFilePath, FileMode.Create))
    {
        foreach (MyStructData myData in myStructDataList)
        {
            newBuffer = getBytes(myData);
            myFileStream.Write(newBuffer, 0, newBuffer.Length);
            bytesWritten += newBuffer.Length;
        }
    }
    

    【讨论】:

    • 当我在我的代码中编写第二行时,它给了我一个错误。它将 myFileStream 中的 Write 函数识别为 void,因此它根本不返回任何 int 值。
    • 谢谢!!!这很好,现在我去解决我的下一个问题,所以我希望我不会打扰大家
    【解决方案2】:

    我认为您不应该将数据写入这样的文件。对于这样一个简单的结构,你最好使用BinaryFormatter

    这是一个例子。首先,您需要通过添加[Serializable] 属性使MyStructData 可序列化:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    [Serializable]
    public struct MyStructData
    {
        public short Id;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
        public string Name;
    }
    

    然后您可以将这些结构的列表写入文件,如下所示:

    List<MyStructData> data = new List<MyStructData>();
    
    for (short i = 0; i < 100; ++i)
        data.Add(new MyStructData{Id = i, Name = i.ToString()});
    
    string filename = "C:\\test\\test.data";
    
    using (var file = File.OpenWrite(filename))
    {
        var writer = new BinaryFormatter();
        writer.Serialize(file, data); // Writes the entire list.
    }
    

    你可以像这样读回它们:

    using (var file = File.OpenRead(filename))
    {
        var reader = new BinaryFormatter();
        data = (List<MyStructData>) reader.Deserialize(file); // Reads the entire list.
    }
    
    foreach (var item in data)
        Console.WriteLine("Id = {0}, Name = {1}", item.Id, item.Name);
    

    如果您将编组添加到结构的唯一原因是您可以在文件中写入和读取它,那么您可以将其删除,以便您的结构看起来像这样:

    [Serializable]
    public struct MyStructData
    {
        public short Id;
        public string Name;
    }
    

    [编辑]

    我来自未来注意到BinaryFormatteris now considered insecure

    BinaryFormatter 类型很危险,不推荐用于数据 加工。应用程序应尽快停止使用 BinaryFormatter 可能,即使他们相信他们正在处理的数据是 值得信赖。 BinaryFormatter 不安全,无法确保安全。

    一个更好的现代二进制序列化格式是MessagePack-CSharp,可通过 NuGet 获得。

    【讨论】:

    • 这看起来不错...我不知道是否应该使用它,因为这是发送文件的测试,也许我必须将结构更改为更复杂的东西。
    • @MarialvyMartínez BinaryFormatter 可以处理相当复杂的事情。它无法处理的是与非托管资源(例如窗口句柄)相关的事情,但我不应该认为你会序列化这些。我只推荐 BinaryFormatter,因为它使用起来相当简单。为了更好地控制,您可以使用 XmlSerializer。不管怎样,你真的不应该仅仅为了序列化而自己编组数据!编组实际上是为了将数据传递给非托管代码。
    • 我强烈建议您在做决定之前阅读此内容:msdn.microsoft.com/en-us/library/vstudio/ms233843.aspx 我可以说一件事:使用 Marshal 进行序列化是非常错误的。
    • 我找到了另一种方法,但使用BinaryWriter,我现在尝试了它,它也可以完美运行。我有保留意见,因为我在这里某处读到BinaryFormatter 也有一些问题。但我认为做出这些选择是因为你对它感到满意:)
    • 使用 BinaryFormatter 或 XmlSerializer(以及 DataContacts)——后者是最“现代”的,但 XmlSerializer 会增加数据大小,因此您可能还需要对其进行压缩。
    猜你喜欢
    • 2022-01-10
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多