【问题标题】:Creating zipFile exhausts memory创建 zipFile 会耗尽内存
【发布时间】:2016-05-03 06:23:31
【问题描述】:

我有 ASP.NET Web API 项目,用户可以在其中从数据库下载一些东西。 我的下载控制器从数据库实例中获取数据。每个结果都有一个 blob 字段,它是某种数据 (1)。 我想将每个结果添加到 ZIP 文件 (2)。毕竟我发送 HTTP 响应添加了我的流内容。

List<Result> results = m_Repository.GetResultsForResultId(given_id_by_request);

// 1
foreach (Result result in results)
{
    string fileName = String.Format("{0}-{1}.bin", id >> 16, result.Id);
    zipFile.AddEntry(fileName, result.Value);
}

// 2
PushStreamContent pushStreamContent = new PushStreamContent((stream, content, context) =>
{
    zipFile.Save(stream);
    stream.Close();
}

response = new HttpResponseMessage(HttpStatusCode.OK) { Content = pushStreamContent };

效果很好!但是对于大的下载请求,这会耗尽我的记忆。我需要找到一种方法将流放入无缓冲的 zip 存档中。有人可以帮帮我吗?!

【问题讨论】:

标签: c# asp.net-web-api


【解决方案1】:

据我从您发布的代码中可以看出,您并没有在使用后处理您创建的流。这可能会增加您的应用保留的大量内存,这可能会导致您出现问题。

我正在使用ZipArchive 将多个文件放入我的 Web 应用程序中的一个 zip 文件中。代码看起来有点像:

using (var compressedFileStream = new MemoryStream())
        {
            using (var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false))
            {
                foreach (Result result in results)
                {
                    string fileName = String.Format("{0}-{1}.bin", id >> 16, result.Id);
                    var zipEntry = zipArchive.CreateEntry(fileName);

                    using (var originalFileStream = new MemoryStream(result.Value))
                    {
                        using (var zipEntryStream = zipEntry.Open())
                        {
                            originalFileStream.CopyTo(zipEntryStream);
                        }
                    }
                }
            }

            return File(compressedFileStream.ToArray(), "application/zip", string.Format("Download_{0:ddMMyyy_hhmm}.zip", DateTime.Now));
}

我在 MVC 控制器方法中使用该代码 sn-p,因此您必须根据您的情况调整返回部分。

以上代码在我的应用程序中运行良好,最多可容纳 300 个条目或 50MB 容量(这些是我的应用程序要求设置的限制)。

希望对你有所帮助。

编辑:忘记了第一个 using 块的右括号。 return 语句必须在这个 using 块内,否则流将被释放。

【讨论】:

  • 非常感谢sn-p。我会尽力!返回值必须是一个以 HttpContent 作为内容类型的 HttpResponse。也许我会让它运行: response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(compressedFileStream) };
  • 应该可以。也许将响应的 ContentType 设置为“application/octet-stream”也是一个好主意
  • 我添加了 response = new HttpResponseMessage(HttpStatusCode.OK) { Content = new StreamContent(compressedFileStream) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); response.Content.Headers.Add("x-filename", string.Format("{0}.zip", request.Filename));返回响应;不幸的是没有成功。
  • 有什么问题?您是否在创建 StreamContent 之前将压缩文件流设置为位置 0?没有它,流指针指向流的末尾。 compressedFileStream.Seek(0, SeekOrigin.Begin) 应该是诀窍。
  • 或 ContentDisposition 可能会导致问题。也许它需要设置为这样的:result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = "test.exe" };
猜你喜欢
  • 2010-09-15
  • 1970-01-01
  • 2015-08-23
  • 2012-11-10
  • 2012-08-19
  • 2011-02-09
  • 2015-10-01
  • 2018-12-11
  • 1970-01-01
相关资源
最近更新 更多