【发布时间】:2023-01-26 07:11:41
【问题描述】:
我正在尝试从文件列表中并行创建一个 Zip 并将其流式传输到客户端。
我有一个工作代码,我在其中按顺序迭代文件,但我希望它被并行压缩(多个文件每个 >100mb)。
using ZipArchive zipArchive = new(Response.BodyWriter.AsStream(), ZipArchiveMode.Create, leaveOpen: false);
for (int i = 0; i < arrLocalFilesPath.Length; i++) // iterate over files
{
string strFilePath = arrLocalFilesPath[i]; // list of files path
string strFileName = Path.GetFileName(strFilePath);
ZipArchiveEntry zipEntry = zipArchive.CreateEntry(strFileName, CompressionLevel.Optimal);
using Stream zipStream = zipEntry.Open();
using FileStream fileStream = System.IO.File.Open(strFilePath, FileMode.Open, FileAccess.Read);
fileStream.CopyTo(zipStream);
}
return new EmptyResult();
Parallel.For 和Parallel.ForEach 不适用于ZipArchive
由于ZipArchive 不是线程安全的,我正在尝试使用DotNetZip 来完成此任务。
我查看了docs,这是我目前使用的DotNetZip
using Stream streamResponseBody = Response.BodyWriter.AsStream();
Parallel.For(0, arrLocalFilesPath.Length, i =>
{
string strFilePath = arrLocalFilesPath[i]; // list of files path
string strFileName = Path.GetFileName(strFilePath);
string strCompressedOutputFile = strFilePath + ".compressed";
byte[] arrBuffer = new byte[8192]; //[4096];
int n = -1;
using FileStream input = System.IO.File.OpenRead(strFilePath);
using FileStream raw = new(strCompressedOutputFile, FileMode.Create, FileAccess.ReadWrite);
using Stream compressor = new ParallelDeflateOutputStream(raw);
while ((n = input.Read(arrBuffer, 0, arrBuffer.Length)) != 0)
{
compressor.Write(arrBuffer, 0, n);
}
input.CopyTo(streamResponseBody);
});
return new EmptyResult();
但是,这不会压缩文件并发送到客户端(它只会在服务器上创建本地 zip 文件)。
使用 MemoryStream 或创建本地 zip 文件是不可能的,也不是我想要的。
服务器应该无缝地流式传输文件的读取字节,即时将其压缩并将其作为块发送给客户端(就像在我的ZipArchive 中一样),但并行读取这些文件并创建它们的 zip 的额外好处。
我知道并行性通常不是 I/O 的最佳选择(有时更糟),但对于这种情况,并行压缩多个大文件应该更快。
我也尝试使用SharpZipLib但没有成功。
使用任何其他库都很好,只要它可以无缝读取文件并将其流式传输到客户端而不影响内存。
任何帮助表示赞赏。
【问题讨论】:
标签: c# asp.net-core parallel-processing stream zip