2011-03-30 76 views
0

假設我有一個對象叫做data,它包含各種信息。讓我們假設data圖中實際上有相當多的東西。C#對象序列化的元信息

如果我使用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位操作系統上,string的上限大約爲2GB,而32位操作系統的上限要小得多。流是否有這樣的限制?由於數據流是以字節爲單位寫入的,所以它們不會。

回答

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. 該被選定在設計過程的早期隨機識別該文件作爲以正確的格式被短字符串。

  2. 一個文件版本號,所以我們可以在將來更改格式並仍然讀取舊的文件。

  3. 以純文本形式顯示的各種業務特定的摘要信息將顯示在列表中,以便用戶知道即使文件名稱已更改也要打開哪個文件。顯然,這不是安全敏感數據。

  4. 一個指示符,表明文件是加密的還是壓縮的,還是兩者兼有。此外,它可以作爲一個整體或逐行進行加密,以支持即時附加加密數據。純文本選項用於開發目的和偶爾的數據手術操作,但由於這種設計,它可以像任何其他文件一樣自動讀取或寫入。

  5. 如果文件是用AES加密的,那麼加密密鑰就存儲在下一個,它本身是用RSA加密的,並用base-64進行序列化。

  6. ASCII 0x02 START OF TEXT字符,純粹是爲了好玩。 (雖然如果它不在那裏,那麼讀取文件將失敗。)

然後傳來數據流。

+1

謝謝:)我沒有想過寫頭字節 - 但現在我明白了。他們說事後總是20/20。 – Ozzah 2011-03-30 23:58:08