在内存中创建 Zip 存档,并从网络返回它 api
Creating Zip Archive in memory, and returning it from a web api
所以我正在尝试创建一个 zip 存档并 return 它来自我的网站 api。从 angular 2 站点调用控制器。目前已创建 zip 文件,但当我打开它时,我收到一条无效消息。最初我在 using 语句中有流,但不得不更改它,因为它们在请求完成之前被处理。
我需要的是创建 zip 文件,将 csv 文件添加到其内容中。然后 return 压缩文件。但是 zip 文件总是无效的。我已经阅读过需要处理 zip 存档以便写入其内容,但我不确定实现此目的的最佳方法是什么。感谢您的指导。
public async Task<IHttpActionResult> ExportReport(int id, ReportModel report)
{
try
{
var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
if (result != null)
{
var compressedFileStream = new MemoryStream();
var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false);
var zipEntry = zipArchive.CreateEntry("textExport.csv");
var origionalFileSteam = new MemoryStream(result.ExportToBytes());
var zipEntryStream = zipEntry.Open();
origionalFileSteam.CopyTo(zipEntryStream);
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(compressedFileStream)};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Export.zip"
};
var t = compressedFileStream.CanRead;
return ResponseMessage(response);
}
return NotFound();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
对使用声明的回应:
有一次我将所有内容都包含在 using 语句中,但响应会失败,因为流已被处理掉。你可以在下面看到这个。
public async Task<IHttpActionResult> ExportReport(int id, ReportModel report)
{
try
{
var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
if (result != null)
{
var compressedFileStream = new MemoryStream();
var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false);
//Create a zip entry for each attachment
var zipEntry = zipArchive.CreateEntry("textExport.csv");
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
using (var zipEntryStream = zipEntry.Open()) {
//Copy the attachment stream to the zip entry stream
originalFileStream.CopyTo(zipEntryStream);
}
compressedFileStream.Position = 0;
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(compressedFileStream)};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Export.zip"
};
return ResponseMessage(response);
}
return NotFound();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
您缺少一些 using(){}
个方块。
确保以正确的顺序关闭 originalFileSteam、zipEntryStream 和 zipArchive。
为了保险起见,请重置内存流。我不知道是否需要这样做,但不会有什么坏处。
//using (var compressedFileStream = new MemoryStream())
var compressedFileStream = new MemoryStream();
using (var zipArchive = new ZipArchive(...))
{
//Create a zip entry for each attachment
var zipEntry = zipArchive.CreateEntry("textExport.csv");
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
using (var zipEntryStream = zipEntry.Open())
{
//Copy the attachment stream to the zip entry stream
originalFileStream.CopyTo(zipEntryStream);
}
}
//compressedFileStream .Position = 0;
var responseBytes =new MemoryStream(compressedFileStream.ToArray());
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(responseBytes )};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return ResponseMessage(response);
处理 zip 存档时正在处理内存流。
您应该处理存档以强制其将内容写入其底层内存流,但请注意以下几点
ZipArchive.Dispose()
Unless you construct the object by using the ZipArchive(Stream, ZipArchiveMode, Boolean)
constructor overload and set its leaveOpen
parameter to true
, all underlying streams are closed and no longer available for subsequent write operations.
When you are finished using this instance of ZipArchive
, call Dispose()
to release all resources used by this instance. You should eliminate further references to this ZipArchive
instance so that the garbage collector can reclaim the memory of the instance instead of keeping it alive for finalization.
并且由于您想继续使用内存流,因此您需要确保它保持打开状态并重置流指针,以便可以从头读取它。
public async Task<IHttpActionResult> ExportReport(int id, ReportModel report) {
try {
var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
if (result != null) {
var compressedFileStream = new MemoryStream();
using(var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create,
leaveOpen: true)) { //<--This is important to keep stream open
//Create a zip entry for each attachment
var zipEntry = zipArchive.CreateEntry("textExport.csv");
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
using (var zipEntryStream = zipEntry.Open()) {
//Copy the attachment stream to the zip entry stream
await originalFileStream.CopyToAsync(zipEntryStream);
}
}// disposal of archive will force data to be written/flushed to memory stream.
compressedFileStream.Position = 0;//reset memory stream position.
var response = new HttpResponseMessage(HttpStatusCode.OK) {
Content = new StreamContent(compressedFileStream)
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
FileName = "Export.zip"
};
return ResponseMessage(response);
}
return NotFound();
} catch (Exception ex) {
return InternalServerError(ex);
}
}
所以我正在尝试创建一个 zip 存档并 return 它来自我的网站 api。从 angular 2 站点调用控制器。目前已创建 zip 文件,但当我打开它时,我收到一条无效消息。最初我在 using 语句中有流,但不得不更改它,因为它们在请求完成之前被处理。
我需要的是创建 zip 文件,将 csv 文件添加到其内容中。然后 return 压缩文件。但是 zip 文件总是无效的。我已经阅读过需要处理 zip 存档以便写入其内容,但我不确定实现此目的的最佳方法是什么。感谢您的指导。
public async Task<IHttpActionResult> ExportReport(int id, ReportModel report)
{
try
{
var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
if (result != null)
{
var compressedFileStream = new MemoryStream();
var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false);
var zipEntry = zipArchive.CreateEntry("textExport.csv");
var origionalFileSteam = new MemoryStream(result.ExportToBytes());
var zipEntryStream = zipEntry.Open();
origionalFileSteam.CopyTo(zipEntryStream);
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(compressedFileStream)};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Export.zip"
};
var t = compressedFileStream.CanRead;
return ResponseMessage(response);
}
return NotFound();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
对使用声明的回应:
有一次我将所有内容都包含在 using 语句中,但响应会失败,因为流已被处理掉。你可以在下面看到这个。
public async Task<IHttpActionResult> ExportReport(int id, ReportModel report)
{
try
{
var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
if (result != null)
{
var compressedFileStream = new MemoryStream();
var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Update, false);
//Create a zip entry for each attachment
var zipEntry = zipArchive.CreateEntry("textExport.csv");
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
using (var zipEntryStream = zipEntry.Open()) {
//Copy the attachment stream to the zip entry stream
originalFileStream.CopyTo(zipEntryStream);
}
compressedFileStream.Position = 0;
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(compressedFileStream)};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Export.zip"
};
return ResponseMessage(response);
}
return NotFound();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
您缺少一些 using(){}
个方块。
确保以正确的顺序关闭 originalFileSteam、zipEntryStream 和 zipArchive。
为了保险起见,请重置内存流。我不知道是否需要这样做,但不会有什么坏处。
//using (var compressedFileStream = new MemoryStream())
var compressedFileStream = new MemoryStream();
using (var zipArchive = new ZipArchive(...))
{
//Create a zip entry for each attachment
var zipEntry = zipArchive.CreateEntry("textExport.csv");
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
using (var zipEntryStream = zipEntry.Open())
{
//Copy the attachment stream to the zip entry stream
originalFileStream.CopyTo(zipEntryStream);
}
}
//compressedFileStream .Position = 0;
var responseBytes =new MemoryStream(compressedFileStream.ToArray());
var response = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(responseBytes )};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return ResponseMessage(response);
处理 zip 存档时正在处理内存流。
您应该处理存档以强制其将内容写入其底层内存流,但请注意以下几点
ZipArchive.Dispose()
Unless you construct the object by using the
ZipArchive(Stream, ZipArchiveMode, Boolean)
constructor overload and set itsleaveOpen
parameter totrue
, all underlying streams are closed and no longer available for subsequent write operations.When you are finished using this instance of
ZipArchive
, callDispose()
to release all resources used by this instance. You should eliminate further references to thisZipArchive
instance so that the garbage collector can reclaim the memory of the instance instead of keeping it alive for finalization.
并且由于您想继续使用内存流,因此您需要确保它保持打开状态并重置流指针,以便可以从头读取它。
public async Task<IHttpActionResult> ExportReport(int id, ReportModel report) {
try {
var result = await ReportGenerationService.ExportReportForId(id, report.Page, report.PageSize, report.SortField, report.SortDir, report.SearchTerm, report.StartDate, report.EndDate, report.UserId, report.TeamId, report.SelectedDateItem);
if (result != null) {
var compressedFileStream = new MemoryStream();
using(var zipArchive = new ZipArchive(compressedFileStream, ZipArchiveMode.Create,
leaveOpen: true)) { //<--This is important to keep stream open
//Create a zip entry for each attachment
var zipEntry = zipArchive.CreateEntry("textExport.csv");
//Get the stream of the attachment
using (var originalFileStream = new MemoryStream(result.ExportToBytes()))
using (var zipEntryStream = zipEntry.Open()) {
//Copy the attachment stream to the zip entry stream
await originalFileStream.CopyToAsync(zipEntryStream);
}
}// disposal of archive will force data to be written/flushed to memory stream.
compressedFileStream.Position = 0;//reset memory stream position.
var response = new HttpResponseMessage(HttpStatusCode.OK) {
Content = new StreamContent(compressedFileStream)
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
FileName = "Export.zip"
};
return ResponseMessage(response);
}
return NotFound();
} catch (Exception ex) {
return InternalServerError(ex);
}
}