1

アレクセイからのフィードバックに続いて、質問を単純化します。

Convert.ToBase64String() を使用せずに、CryptoStream (ToBase64Transform を使用) の内容を StreamWriter (Unicode エンコーディング) に変換するために、バッファリングされた Stream アプローチを使用するにはどうすればよいですか?

注: Convert.ToBase64String() を呼び出すと OutOfMemoryException がスローされるため、変換にはバッファー/ストリーム アプローチが必要です。

4

2 に答える 2

2

おそらく、 TextWriterStreamではなくcustom を実装する必要があります。ライターよりもストリームを構成する方がはるかに簡単です (ストリームを圧縮ストリームに渡すなど)。

Streamカスタム ストリームを作成するには、少なくともWriteand Flush(およびReadR/W ストリームが必要な場合)から派生させて実装します。残りは多かれ少なかれオプションであり、追加のニーズに依存します。他のストリームへの通常のコピーには他に何も必要ありません。

  • コンストラクターで、書き込み用に渡された内部ストリームを取得します。Base64 は常に ASCII 文字を生成するため、出力を BOM の有無にかかわらず UTF-8 としてストリームに直接書き込むのは簡単ですが、エンコーディングを指定する場合は、内部ストリームをStreamWriter内部でラップできます。

  • Write実装では、3 バイトの倍数 (つまり 300) のブロックを持つのに十分なバイトが得られるまでデータをバッファリングし、その部分を呼び出しますConvert.ToBase64String。未変換部分を紛失しないように注意してください。Base64 は 3 バイトを 4 文字に変換するため、3 の倍数のサイズのブロックに変換すると、最後に=/==パディングがなく、次のブロックと連結できます。その変換された部分を内部ストリーム/ライターに書き込みます。3*10000大きなオブジェクト ヒープへのブロックの割り当てを避けるために、ブロック サイズを比較的小さいサイズに制限する必要があることに注意してください。

  • 最後に書き込まれていないバイト (これFlushは最後にパディングがある唯一のバイトになります) を変換し、=それもストリームに書き込むようにしてください。

  • 読み取りには、Base64 では空白が許可されているため、より注意する必要がある場合があります。そのため、固定数の文字を読み取ってバイトに変換することはできません。最も簡単な方法は、文字単位で読み取り、StreamReaderスペース以外の 4 つをそれぞれバイトに変換することです。

注: バイトから直接手動で Base64 の書き込み/読み取りを検討できます。パフォーマンス上の利点はいくらかありますが、ビット シフトが苦手な場合は難しいかもしれません。

于 2013-10-15T16:37:44.147 に答える
0

以下を使用して暗号化してみてください。入力として fileName/filePath を使用しています。必要に応じて調整できます。これを使用して、メモリ不足の例外なく、1 GB 以上のファイルを正常に暗号化しました。

public bool EncryptUsingStream(string inputFileName, string outputFileName)
        {
            bool success = false;

            // here assuming that you already have key
            byte[] key = new byte[128];

            SymmetricAlgorithm algorithm = SymmetricAlgorithm.Create();
            algorithm.Key = key;

            using (ICryptoTransform transform = algorithm.CreateEncryptor())
            {
                CryptoStream cs = null;
                FileStream fsEncrypted = null;
                try
                {
                    using (FileStream fsInput = new FileStream(inputFileName, FileMode.Open, FileAccess.Read))
                    {
                        //First write IV 
                        fsEncrypted = new FileStream(outputFileName, FileMode.Create, FileAccess.Write);
                        fsEncrypted.Write(algorithm.IV, 0, algorithm.IV.Length);

                        //then write using stream
                        cs = new CryptoStream(fsEncrypted, transform, CryptoStreamMode.Write);
                        int bytesRead;
                        int _bufferSize = 1048576; //buggersize = 1mb; 
                        byte[] buffer = new byte[_bufferSize];
                        do
                        {
                            bytesRead = fsInput.Read(buffer, 0, _bufferSize);
                            cs.Write(buffer, 0, bytesRead);
                        } while (bytesRead > 0);

                        success = true;

                    }
                }
                catch (Exception ex)
                {
                    //handle exception or throw.
                }
                finally
                {
                    if (cs != null)
                    {                       
                        cs.Close();
                        ((IDisposable)cs).Dispose();                    

                        if (fsEncrypted != null)
                        {
                            fsEncrypted.Close();
                        }
                    }

                }
            }
            return success;
        }
于 2013-10-14T16:44:38.393 に答える