C#类转换为字节流。

3
什么是将我的类转换为/从字节数组的正确方法?我想尽可能简单地将其保存到文件中等操作。
我应该使它可序列化吗? 我只需提供返回字节数组的函数吗?或者使用MemoryStream? 还是其他什么方法?
我对C#文件处理不是特别熟悉,因此如果答案还可以展示写入二进制数据到文件的通用方式,我会很感激。
编辑:从答案中我看到我的问题被误解了。我有一个类。我有一个希望以二进制形式保存的格式。我想知道公开这种二进制表示的正确方法是什么。我需要完全控制格式,而不是让.NET为我完成(我稍后将在c++中读取它)。

11
在.NET中搜索“二进制序列化”。这是一个简单的参考材料。 - Noldorin
@baunch:如果你需要完全控制一个protobuf(在我的答案中提到),那么它是可能的选择之一。 - Tigran
@Tigran 澄清一下:protobuf并不能提供“完全控制”,但它在C#和C++之间非常容易移植。 - Marc Gravell
@Tigran 有些疯狂的白痴仍然需要编写/移植该库(紧张地四处张望……) - Marc Gravell
@MarcGravell: :) 我说的是“小概率”。总会有需要这样做的情况,但这个问题对我来说似乎不是这种情况。 - Tigran
显示剩余3条评论
6个回答

3

看看Protobuf,它很容易理解和开始编码,以立即查看结果。但是之后,自然而然地,阅读不同的文章来选择最适合您需求的内容。


3
按照优先顺序:
1)如果您的应用程序具备数据库功能,则将要“记住”的数据存储到数据库中。
2)一个简单的平面文件或XML文件(即“不序列化:只保存状态”)
3)否则,序列化可能是您正在寻找的内容。
这里是一个关于.Net序列化的链接:

http://msdn.microsoft.com/en-us/library/ms973893.aspx

这里是一个关于将数据序列化为XML(而不是二进制)的链接:

http://support.microsoft.com/kb/815813

using System;

public class clsPerson
{
  public  string FirstName;
  public  string MI;
  public  string LastName;
}

class class1
{ 
   static void Main(string[] args)
   {
      clsPerson p=new clsPerson();
      p.FirstName = "Jeff";
      p.MI = "A";
      p.LastName = "Price";
      System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
      x.Serialize(Console.Out, p);
      Console.WriteLine();
      Console.ReadLine();
   }
}    

再次强烈建议将“序列化”作为最后一招(如果可能,尽可能简单和稳健地保存状态),并且将“二进制序列化”作为非常最后的手段(除非你有非常好的理由不这样做)。

在我看来...


1
你能解释一下“使用平面文件保存状态”的意思吗?我不明白这与二进制序列化的区别。 - Baruch

2
根据您的编辑和您拥有二进制格式并需要自行控制的事实,我认为有两个选项:
  • 接受流并将二进制表示写入流的方法
  • 返回字节数组的方法
当然,您可以通过创建另一个类来将其与类型本身解耦,该类具有:
  • 接受您类型的实例和流并将二进制表示写入流的方法
  • 接受您类型的实例并返回字节数组的方法
每对中的第一个选项可能会给您更多的灵活性; 根据您的需求,您可以传递文件流或内存流等。

2

您可以使用 BinaryFormatter。请注意,您的类必须是[Serializable]才能正常使用。

private byte[] ToByteArray(object source)
{
    var formatter = new BinaryFormatter();
    using (var stream = new MemoryStream())
    {
        formatter.Serialize(stream, source);                
        return stream.ToArray();
    }
}

1
将关键数据以文本形式写入磁盘总是很危险的。任何匿名用户都可以打开文本文件并轻松读取您的数据。使用对象序列化,您可以在一定程度上减少这种危险。您可以直接将任何复杂对象写入 filestream 而不需要将各个属性的值转换为文本。您可以使写入磁盘的数据至少不可读。为了让用户读取您的数据文件,他们必须使用您的程序。就像您可能在应用程序中提供的“文件打开”命令一样。 序列化 是将复杂对象转换为字节流进行存储的过程。 反序列化 是其相反的过程,即将字节流解包成它们的原始形式。用于读写文件的命名空间是 System.IO。对于序列化,我们将查看 System.Runtime.Serialization 命名空间。 ISerializable 接口允许您使任何类可序列化。请参阅其中有良好的示例。
如上所述,序列化是将对象转换为字节流的过程,以便将其持久化到内存、数据库或文件中。它的主要目的是保存对象的状态,以便在需要时能够重新创建它。相反的过程称为反序列化序列化的工作原理 下面的插图展示了序列化的整个过程。

enter image description here

对象被序列化为一个流,其中不仅包含数据,还包括有关对象类型的信息,例如其版本、文化和程序集名称。从该流中,可以将其存储在数据库、文件或内存中。请参见MSDN

0
如果您想使用二进制序列化来序列化一个类,可以参考下面的代码:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace BinarySerializationTest
{
    class Program
    {
        static void Main(string[] args)
        {

            // Serialization of String Object   

            String writeData = "Microsoft .NET Framework 4.0";
            FileStream writeStream = new FileStream("C:\\StringObject.data", FileMode.Create);
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(writeStream, writeData);
            writeStream.Close();

            // Deserialization of String Object

            FileStream readStream = new FileStream("C:\\StringObject.data", FileMode.Open);
            String readData = (String) formatter.Deserialize(readStream);
            readStream.Close();
            Console.WriteLine(readData);

            Console.Read();
        }
    }
}

在这个例子中,我序列化了一个字符串,但你可以序列化“任何对象”。你需要做的就是在你的类上添加属性[Serializable]
[Serializable]
public class Car
{
    public string Make;
    public string Model;

}

如果你想实现自定义序列化,你的类需要实现 ISerializable 接口。

http://msdn.microsoft.com/en-us/library/ms182342(v=VS.100).aspx


我想要能够序列化我的类,并且我想要控制序列化格式。 - Baruch
你可以使用XML格式或二进制格式对你的类进行序列化。 - Massimiliano Peluso

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接