0

假设我有一个名为的对象data,其中包含各种信息。让我们说一下,data图中实际上有很多东西。

如果我使用它进行序列化,BinaryFormatter那么我会得到一个文件,例如 5Mb。如果我将序列化流封装在一个中,GZipStream那么我会得到一个小得多的文件,比如 1Mb。

如果需要,我可以在压缩流的同时加密流,或者在不压缩流的情况下加密流。

问题是:我需要知道在序列化过程中做了什么,以便在反序列化时知道该怎么做。

一种技术是使用不同的文件扩展名。例如,未压缩、未加密的文件可能具有 .dat 扩展名,.zdat 表示压缩,.cdat 表示加密,.czdat 表示压缩和加密。

这会起作用,但它会带来一个潜在的问题:如果用户更改扩展名等怎么办。这也意味着如果我想在 Windows 中关联文件,则需要关联 4 个扩展名而不是 1 个 - 将与现有协会发生冲突的风险。

如果我将我的数据对象包装在一个简单的类中:

[Serializable]
public class SerialisationContainer
{
   public string SerialisedData { get; private set; }

   public bool Compressed { get; private set; }
   public bool Encrypted { get; private set; }

   public SerialisationContainer()
   {
     // etc...
   }

   public object GetObject()
   {
     // etc...
   }
}

然后我基本上序列化一个对象,其中有一个序列化流,它可能被压缩和/或加密,但我们现在不知道也不关心,因为元信息存储在SerialisationContainer.

你怎么看?我基本上只是好奇你对这种方法的看法,以及在类似情况下你会做什么。我认为上述方法是一种非常浪费的方式来做我想做的事。我基本上需要将我的数据图序列化为内存流,将其转换为字符串,将字符串放入容器中,然后再次序列化。

另一个问题是string SerialisedData. 在我给出的示例中,我们只有大约 5Gb 的 BinaryData,但是当它开始变大时呢?我知道 64 位操作系统上的 a 上限string约为 2GB,而 32 位操作系统的上限要小得多。流有这样的限制吗?由于流是以字节块的形式写入的,因此它们不会写入是有道理的。

4

2 回答 2

1

首先,懒惰的解决方案:您不必直接序列化到文件。您可以序列化到内存,然后编写一个具有 1 字节格式的文件,然后是序列化数据。

其次,你可以变得更聪明一点:打开一个文件;向其写入一个字节(格式);序列化成同一个字符串。反序列化,读取一个字节找出格式,然后将流传递给反序列化器;它只会在那一个字节之后读取数据。

如果你有方法

void SerializeToStream(Stream stream, bool compress, bool encrypt);
void DeserializeFromStream(Stream stream, bool compressed, bool encrypted);

您的代码可能如下所示:

// Could also use a flags enum for these
const int EncryptBit = 1;
const int CompressBit = 2;

public void SaveToFile(string filename, bool compress, bool encrypt) {
    byte format = (byte)((compress ? CompressBit : 0) | (encrypt ? EncryptBit : 0));
    using (Stream stream = File.OpenWrite(filename)) {
        stream.WriteByte(format);
        SerializeToStream(stream, compress, encrypt);
    }
}

public void LoadFromFile(string filename) {
    using (Stream stream = File.OpenRead(filename)) {
        int format = stream.ReadByte();
        if (format < 0 || format >= 4) {
            throw new InvalidOperationException("Unknown file format");
        }

        bool compressed = format & CompressBit != 0;
        bool encrypted = format & EncryptBit != 0;
        DeserializeFromStream(stream, compressed, encrypted);
    }
}
于 2011-03-30T23:27:31.337 回答
1

有一次我就处于那种情况。我为手动写出的文件创建了一个标题,然后是压缩和/或加密(或可能是纯文本)流。当我打开文件时,我首先读取标题,然后根据该信息将输入流的位置设置为数据的开头,然后从中创建解压缩和/或解密流。它就像一个魅力,是小菜一碟,还有其他一些陈词滥调。

我的标题是纯文本,包括:

  1. 在设计过程的早期随机选择的一个短字符串,用于将文件标识为正确的格式。

  2. 文件版本号,因此我们可以在将来更改格式并仍然读取旧文件。

  3. 以纯文本形式显示的各种特定于业务的摘要信息将显示在列表中,因此即使文件名已更改,用户也可以知道要打开哪个文件。显然,这不是安全敏感数据。

  4. 指示文件是否已加密、压缩或两者兼有的指示符。此外,它可以作为一个整体或逐行加密,以支持动态附加加密数据。纯文本选项用于开发目的和偶尔的数据手术操作,但由于这种设计,它可以像任何其他文件一样被自动读取或写入。

  5. 如果文件使用 AES 加密,则接下来存储加密密钥,该密钥本身使用 RSA 加密,并使用 base-64 序列化。

  6. ASCII 0x02 START OF TEXT 字符,纯粹是为了好玩。(虽然如果它不存在,那么读取文件将会失败。)

然后是数据流。

于 2011-03-30T23:30:14.090 回答