2つのこと。まず、現在のコード設計を維持する場合は、エントリに書き込む前に MemoryStream で Seek() を実行する必要があります。
dt.TableName = "Declaration";
MemoryStream stream = new MemoryStream();
dt.WriteXml(stream);
stream.Seek(0,SeekOrigin.Begin); // <-- must do this after writing the stream!
using (ZipFile zipFile = new ZipFile())
{
zipFile.AddEntry("Report.xml", "", stream);
Response.ClearContent();
Response.ClearHeaders();
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");
zipFile.Save(Response.OutputStream);
}
この設計を維持する場合でも、Dispose() を呼び出す代わりに、すべてのDotNetZip の例で示したように、using() 句を使用することをお勧めします。using() 句は、障害が発生した場合の信頼性が高くなります。
AddEntry() を呼び出す前に MemoryStream をシークする必要があるのはなぜでしょうか。その理由は、AddEntry() は、位置が重要なストリームを渡す呼び出し元をサポートするように設計されているためです。その場合、呼び出し元は、ストリームの現在の位置を使用して、ストリームからエントリ データを読み取る必要があります。AddEntry() はそれをサポートしています。したがって、AddEntry() を呼び出す前に、ストリーム内の位置を設定します。
ただし、より良いオプションは、 WriteDelegate を受け入れる AddEntry()のオーバーロードを使用するようにコードを変更することです。これは、データセットを zip ファイルに追加するために特別に設計されました。元のコードは、データセットをメモリ ストリームに書き込み、次にストリームをシークし、ストリームのコンテンツを zip に書き込みます。WriteDelegate を使用すると、データを 1 回書き込むと、より高速で簡単になります。コードは次のようになります。
dt.TableName = "Declaration";
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment; filename=Report.zip");
using(Ionic.Zip.ZipFile zipFile = new Ionic.Zip.ZipFile())
{
zipFile.AddEntry("Report.xml", (name,stream) => dt.WriteXml(stream) );
zipFile.Save(Response.OutputStream);
}
これにより、データセットが zip ファイルの圧縮ストリームに直接書き込まれます。非常に効率的です!ダブルバッファリングなし。匿名デリゲートは、ZipFile.Save() の時点で呼び出されます。1 回の書き込み (+圧縮) のみが実行されます。