假设我有一个名为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...
}
}
然后我基本上序列化了一个对象,该对象中有一个可以压缩和/或加密的序列化流,但我们现在还不知道或不关心,因为元信息存储在{{1 }}
你怎么看?我基本上只是好奇你对这种方法的看法,以及你在类似情况下做了什么。我认为上述方法是一种非常浪费的方式来做我想做的事情。我基本上需要将我的数据图序列化为内存流,将其转换为字符串,将字符串放入我的容器中,然后再次序列化。另一个问题是SerialisationContainer
的长度。在我给出的示例中,我们只有大约5Gb的BinaryData,但是什么时候它开始变大?我知道64位操作系统上string SerialisedData
的上限约为2GB,而32位操作系统的上限则要小得多。溪流有这样的局限吗?由于流是以字节为单位写的,因此它们不会有意义。
答案 0 :(得分: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);
}
}
答案 1 :(得分:1)
我曾经遇到过这种情况。我为我手动编写的文件创建了一个标题,然后是压缩和/或加密(或可能是纯文本)流。当我打开文件时,我首先读入标题,然后根据该信息设置输入流的位置到数据的开头,然后从中创建解压缩和/或未加密的流。它像一个魅力,一块蛋糕,以及其他几个陈词滥调。
我的标题是纯文本,包括:
在设计过程的早期随机选择的短字符串,用于将文件标识为正确的格式。
文件版本号,因此我们可以在将来更改格式,并仍然可以阅读旧文件。
以明文形式显示的各种特定于业务的摘要信息,这些信息将显示在列表中,这样即使文件名已更改,用户也会知道要打开哪个文件。这显然不是安全敏感数据。
指示文件是加密,压缩还是两者都有的指示符。此外,它可以作为一个整体或逐行加密,以支持动态附加加密数据。纯文本选项用于开发目的和偶尔的数据外科操作,但由于这种设计,它可以像任何其他文件一样自动读取或写入。
如果文件是用AES加密的,则接下来存储加密密钥,加密密钥本身用RSA加密,并用base-64序列化。
ASCII 0x02 START OF TEXT字符,纯粹是为了好玩。 (虽然如果不存在,那么阅读文件就会失败。)
然后是数据流。