【发布时间】:2021-03-15 08:22:28
【问题描述】:
我正在开发一个 ASP.NET Core 2.1 API 项目,该项目将由 Angular 应用程序使用,稍后将用于移动应用程序。所需功能之一是压缩和下载文件集合,压缩后的文件会很大(1GB 或更多)。 我现在的代码如下:
- Angular 应用请求 API 并期望得到 blob 响应。
- 服务器上的 API 创建一个 Zip 文件并使用内存流读取它。
- API 使用文件响应返回内存流。
- Angular 中订阅下载服务的方法保存 文件。
现在发生的情况是,当我在浏览器中单击下载按钮时,我必须等待下载完成,然后浏览器会显示允许用户保存并选择保存位置的默认弹出窗口。
我想知道我所做的是否正确,并且将来不会导致任何内存问题?
是否有更好的方法可以流畅地传输文件,因此当下载开始时,浏览器会直接显示保存消息并显示默认浏览器进度条?
角码:
组件点击功能:
download(event,id){
event.stopPropagation();
event.preventDefault();
this.myservice.Downloadservice(avatar_id).subscribe((res: any) => {
saveAs(res.data, res.filename);
});
}
服务代码:
DownloadAllservice(id): Observable<any> {
let authToken = localStorage.getItem('auth_token');
let _options = { headers: new Headers({ 'Authorization': `Bearer ${authToken}`, } ),responseType: ResponseContentType.Blob };
let formData = new FormData();
let options ={
type: "zip",
id: id
};
formData.append('options',JSON.stringify(options));
return this.http.post(this.baseUrl + "/api/Download/", formData, _options)
.map(response =>{
return {
'filename': this.getFileNameFromHttpResponse(response),
'data': response.blob()
} })
.catch(this.handleError);
}
.net核心代码:
[Authorize(Policy = "Admin")]
[DisableRequestSizeLimit]
[HttpPost("Download", Name = "Download")]
public async Task<IActionResult> Download()
{
// get files list then start creating the temp folder and zipped folder
var archive = Path.Combine(Directory.GetDirectoryRoot("wwwroot"), @"home\" + FilePath + @"\temp\" + "filename");
var temp = Path.Combine(Directory.GetDirectoryRoot("wwwroot"), @"home\" + FilePath + @"\temp");
if (!System.IO.Directory.Exists(temp))
{
Directory.CreateDirectory(temp);
}
Directory.CreateDirectory(archive);
try
{
foreach (var file_id in filelist)
{
var path = file.path;
if (!System.IO.File.Exists(Path.Combine(archive, Path.GetFileName(path)))) {
System.IO.File.Copy(path, Path.Combine(archive, Path.GetFileName(path)));
}
}
var archivezip = Path.Combine(Directory.GetDirectoryRoot("wwwroot"), @"home\" + FilePath + @"\temp\" + "filename" + ".zip");
// create a new archive
ZipFile.CreateFromDirectory(archive, archivezip);
var memory = new MemoryStream();
using (var stream = new FileStream(archivezip, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
Directory.EnumerateFiles(archive).ToList().ForEach(f => System.IO.File.Delete(f));
Directory.EnumerateDirectories(archive).ToList().ForEach(f => System.IO.Directory.Delete(f, true));
Directory.Delete(archive);
System.IO.File.Delete(archivezip);
return File(memory, "application/octet-stream","filename.zip");
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.Message);
}
}
请注意,未来不仅 Angular 应用会使用 API,还会添加移动应用
【问题讨论】:
-
这已经导致内存问题 - 它占用了 1GB 的 RAM 来保存可以从磁盘文件中读取的数据。您应该直接返回 ZIP 文件,并在返回后寻找将其删除的方法。这可以像inheriting from one of the FileResult classes 和覆盖
Execute或ExecuteAsync一样简单,以便在下载完成后删除源文件 -
我不敢相信我已经回答了这样一个问题并忘记了它
-
谢谢@PanagiotisKanavos,是的,这是我浪费内存的担忧之一
标签: c# angular asp.net-core asp.net-web-api .net-core