1

ディレクトリを保持したまま、ファイルを Zip ファイルに追加しようとしています。以下のコードは、圧縮する数 100 Mb のファイルがない限り、基本的に機能します。約 250 Mb のファイルを 1 つ含むディレクトリを zip すると (メモリが十分にあるシステム上で)、その行で OutOfMemory 例外が発生しwrite.Write()ます。

ファイル全体の読み取り/書き込み時に最初に失敗したため、チャンクで読み取るようにコードを既に変更しました。なぜまだ失敗するのかわかりませんか?

    using (FileStream zipToOpen = new FileStream(cZipName, eFileMode)) 
        ZipArchiveEntry readmeEntry = archive.CreateEntry(cFileToBackup

);

    using (BinaryWriter writer = new BinaryWriter(readmeEntry.Open()))
    {
        FileStream fsData = null;                                                                // Load file into FileStream
        fsData = new FileStream(cFileFull, FileMode.Open, FileAccess.Read);
        {
            byte[] buffer = new byte[1024];
            int bytesRead = 0;
            while ((bytesRead = fsData.Read(buffer, 0, buffer.Length)) > 0)
            {
                 writer.Write(buffer,0,bytesRead); // here it fails
                 fsData.Flush(); // ->CHANGED  THIS TO writer.Flush() SOLVED IT - nearly..
            }
        }
        fsData.Close();
    }

EDIT:Arkadiusz Kは、ライターではなくリーダーでフラッシュを使用したことは正しかった。それを変更した後、プログラムは最初に 100 Mb で停止した場所で 1 Gb 以上のファイルを圧縮します。ただし、たとえば 6 Gb ファイルを圧縮しようとすると、別の例外が発生します。次のように停止します: System.IO.IOException was unhandled Stream was too long Source=mscorlib StackTrace: at System.IO.MemoryStream.Write(Byte[] buffer 、Int32 オフセット、Int32 カウント) (など)

なぜまだ失敗するのか、誰にも分かりますか?コードは一度に 1 Kb を適切に読み書きする必要があると思いますか?

4

2 に答える 2

7

まず第一に、コードをフォーマットして、できるだけ簡潔にしたいと思います。

var readmeEntry = archive.CreateEntry(cFileToBackup);
using (var fsData = new FileStream(cFileFull, FileMode.Open, FileAccess.Read))
using (var writer = new BinaryWriter(readmeEntry.Open()))
{
    var buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fsData.Read(buffer, 0, buffer.Length)) > 0)
    {
         writer.Write(buffer, 0, bytesRead); // here it fails
         writer.Flush();
    }
}

ここで、失敗する理由を説明します。

BinaryWriter はストリーム ライターです。データをストリームに書き込む必要がある場合、通常は長さのプレフィックスを付けて次のように書き込みます。

長さがプレフィックス付きとは、BinaryWriter インスタンスの現在のエンコーディングでストリームにエンコードされたときに、このメソッドが最初に文字列の長さ (バイト単位) を書き込むことを意味します。この値は、符号なし整数として書き込まれます。次に、このメソッドはそのバイト数をストリームに書き込みます。

ファイルに書き込むために、あなたの場合、データは最初に MemoryStream に書き込まれます。ここで、MemoryStream はバッキング ストア ストリームです。以下の図を参照してください。

.NET のストリーム

(画像はhttp://kcshadow.net/wpdeveloper/sites/default/files/streamd3.pngから取得)

システムのメモリが約 6 ~ 8 GB であるか、アプリケーションにそれだけのメモリしか割り当てられていないため、6 GB のファイルを圧縮しようとすると、バッキング ストア ストリームが最大限に拡張され、それ以降は例外がスローされます。

于 2015-09-15T01:54:36.453 に答える