0

dataさまざまな情報を含む というオブジェクトがあるとします。data議論のために、グラフ内には実際にはかなり多くのものがあるとしましょう。

を使用してシリアル化するBinaryFormatterと、たとえば 5Mb のファイルが得られます。シリアライゼーション ストリームを にカプセル化するとGZipStream、はるかに小さなファイル、たとえば 1Mb が得られます。

必要に応じて、ストリームを圧縮しながら暗号化することも、ストリームを圧縮せずに暗号化することもできます。

問題は、デシリアライズするときに何をすべきかを知るために、シリアライズ中に何が行われたかを知る必要があることです。

1 つの手法は、別のファイル拡張子を使用することです。たとえば、圧縮も暗号化もされていないファイルの拡張子は、.dat で、圧縮されている場合は .zdat、暗号化されている場合は .cdat、圧縮および暗号化されている場合は .czdat になります。

これは機能しますが、潜在的な問題が発生します。ユーザーが拡張子を変更した場合などです。これは、Windows でファイルを関連付ける場合、関連付ける必要がある拡張子が 1 つではなく 4 つあることも意味します。既存の関連付けとの衝突のリスク。

データ オブジェクトを単純なクラスでラップすると、次のようになります。

[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

どう思いますか?私は基本的に、あなたがこの方法についてどう思うか、また同様の状況であなたが何をしているのかに興味があります. 上記の方法は、私がやりたいことをするのに非常に無駄な方法だと思います。基本的に、データ グラフをメモリ ストリームにシリアル化し、それを文字列に変換し、その文字列をコンテナー内に配置してから、再度シリアル化する必要があります。

もう 1 つの問題は、長さですstring SerialisedData。私が示した例では、約 5Gb の BinaryData しかありませんが、それが大きくなり始めるとどうなるでしょうか? 64 ビット OSでの上限stringは約 2GB で、32 ビット OS ではそれよりも大幅に少ないことがわかっています。ストリームにはそのような制限がありますか? ストリームはバイトのブロックで書き込まれるため、そうしないのは理にかなっています。

4

2 に答える 2

1

まず、怠惰な解決策: ファイルに直接シリアル化する必要はありません。メモリにシリアル化してから、1 バイトのフォーマットの後にシリアル化データが続くファイルを書き込むことができます。

次に、もう少し賢くすることができます。ファイルを開きます。それに1バイトを書き込みます(フォーマット)。同じ文字列にシリアル化します。デシリアライズするには、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 に答える