如果你真的在乎內存中,然後在這裏是一個將直接寫入響應流的解決方案。首先定義自定義的ActionResult:
public class SharpZipLibResult : FileResult
{
private readonly string _fileDownloadName;
private readonly string[] _filesToZip;
private const int ChunkSize = 1024;
public SharpZipLibResult(string fileDownloadName, params string[] filesToZip)
: base("application/octet-stream")
{
_fileDownloadName = fileDownloadName;
_filesToZip = filesToZip;
}
protected override void WriteFile(HttpResponseBase response)
{
var cd = new ContentDisposition();
cd.FileName = _fileDownloadName;
response.AddHeader("Content-Disposition", cd.ToString());
response.BufferOutput = false;
using (var zipStream = new ZipOutputStream(response.OutputStream))
{
foreach (var file in _filesToZip)
{
var entry = new ZipEntry(Path.GetFileName(file));
zipStream.PutNextEntry(entry);
using (var reader = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
byte[] buffer = new byte[ChunkSize];
int bytesRead;
while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
{
byte[] actual = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, actual, 0, bytesRead);
zipStream.Write(actual, 0, actual.Length);
}
}
}
}
}
}
有了這個技術,你可以成爲一些非常巨大的zip文件,而無需關心存儲或有清潔您的服務器硬盤的一些臨時zip文件。
最後你的控制器動作看起來是這樣的:
public ActionResult Index()
{
return new SharpZipLibResult(
"result.zip",
@"c:\work\report1.pdf",
@"c:\work\report2.pdf",
@"c:\work\report3.pdf"
);
}
使用這種方法的內存佔用量最小化,因爲拉鍊被直接寫入這方面將通過基礎網絡套接字來表示響應流。
當然取決於你的文件存儲在哪裏SharpZipLibResult
可以調整。這裏我假設這些文件存儲在文件系統中。
您是否重置了流的位置? – 2009-11-06 14:10:14
也許你應該在製作壓縮文件之前估計一下大小,然後在磁盤上使用文件,而不是在文件大的時候保存內存。對於大文件而言,網絡帶寬將成爲瓶頸,而不是磁盤操作。 – Guffa 2009-11-06 14:21:56
@Guffa:爲了仍然使用MemoryStream,會是一個「理智」的大小?該應用程序在4 GB的單個服務器上運行,我不期望高負載,並沒有太多的並行下載。使用內存流對我來說更容易一些,因爲我沒有對舊zip文件進行清理...... – Max 2009-11-06 14:38:28