In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-05 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
如何下载文件并使用Javascript将其压缩在浏览器中,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
与其生成zip文件并从您的服务器进行传输,不如下载数据并将其压缩在浏览器中呢?
我最近从事一个副项目,该项目可根据用户的请求生成报告。对于每个请求,我们的后端将生成一个报告,将其上传到Amazon S3存储,然后将其URL返回给客户端。由于生成报告需要一些时间,因此将存储输出文件,并且服务器将通过请求参数来缓存其URL。如果用户订购相同的商品,则后端将返回现有文件的URL。
几天前,我有一个新要求,我需要下载一个包含数百个报告的zip文件,而不是单个文件。我想到的第一个解决方案是:
在服务器上准备压缩文件
上传到Amazon S3存储
给客户端提供下载URL
但是此解决方案有一些缺点:
生成zip文件的逻辑非常复杂。我需要考虑为每个请求生成所有文件,或者在重用现有文件和生成新文件之间进行组合。两种方法似乎都很复杂。他们将花费一些时间来处理,并且稍后需要大量的编码,测试和维护。
它无法利用我已经构建的功能。尽管zip文件是不同的报告集,但很可能大多数单个报告都是由较早的请求生成的。因此,虽然zip文件本身不太可能可重用,但单个文件却可以重用。使用上述方法,我需要一直重做整个过程,这并不是很有效。
生成一个zip文件需要很长时间。由于我的后端是一个单线程进程,因此此操作可能会阻止其他请求一段时间,并且在此期间可能会超时。
在客户端跟踪流程非常困难,我喜欢在网站上放置进度栏。如果一切都在后端处理,我需要找到其他方法向前端报告状态。这并不容易。
我想节省基础设施的成本。如果我们可以将一些计算转移到前端并降低基础架构的成本,那就太好了。我的客户不介意他们再等几秒钟,还是在笔记本电脑上花费额外的MB RAM。
我想出的最终解决方案是:将所有文件下载到浏览器中,然后将其压缩。在这篇文章中,我将介绍如何做。
免责声明:在这篇文章中,我假设你已经具有有关Javascript和Promise的基本知识。如果你没有,我建议你先了解他们,然后再回到这里:)
下载单个文件
在应用新解决方案之前,我的系统允许下载一个报告文件。有很多方法可以做到这一点,后端可以直接通过HTTP请求响应原始文件的内容,也可以将文件上传到另一个存储设备并返回文件URL。我选择第二种方法,因为我想缓存所有生成的文件。
一旦有了文件URL,在客户端上的工作就非常简单:在新选项卡中打开此URL。浏览器将完成剩下的工作以下载文件。
const downloadViaBrowser = url => { window.open(url, ‘_blank’); }
下载多个文件并存储在内存中
当下载和压缩多个文件时,我们不能再使用上面的简单方法。
如果一个JS脚本试图同时打开许多链接,浏览器会怀疑它是否是一个安全威胁,并警告用户阻止这些行为。虽然用户可以确认继续,但这不是一个好的体验
你无法控制下载的文件,浏览器管理文件内容和位置
解决此问题的另一种方法是使用 fetch 来下载文件并将数据作为Blob存储在内存中。然后,我们可以将其写入文件或将这些Blob数据合并为zip文件。
const download = url => { return fetch(url).then(resp => resp.blob()); };
这个函数返回一个被解析为blob的promise。我们可以结合 Promise.all() 来下载多个文件。Promise.all() 将一次性完成所有的promise,如果所有的子promise都被解析,或者其中一个承诺出现错误,则进行解析。
const downloadMany = urls => { return Promise.all(urls.map(url => download(url)) }
按X文件组下载
但是,如果我们需要一次下载大量文件怎么办?假设有1000个文件?使用 Promise.all() 可能不再是一个好主意,你的代码将一次发送一千个请求。 这种方法有很多问题:
操作系统和浏览器支持的并发连接数是有限的。因此,浏览器一次只能处理几个请求。其他请求放入队列,并且超时计数。结果是,你的大多数请求在发送之前都会超时。
一次发送大量请求也会使后端过载
我考虑过的解决方案是将文件分成多个组。假设我有1000个文件可供下载。而不是通过 Promise.all() 立即开始一次下载所有文件,我将每次下载5个文件。在完成这5个之后,我将开始另一个包,我总共会下载250个包。
要实现这个功能,我们可以做一个自定义逻辑。或者我建议一个更简单的方法,就是利用第三方库bluebirdjs。该库实现了许多有用的Promise函数。在这个用例中,我将使用 Promise.map()。注意这里的Promise现在是库提供的自定义Promise,而不是内置的Promise。
import Promise from 'bluebird'; const downloadByGroup = (urls, files_per_group=5) => { return Promise.map( urls, async url => { return await download(url); }, {concurrency: files_per_group} ); }
通过上面的实现,该函数将接收一个URL数组并开始下载所有URL,每次都具有最大 files_per_group。该函数返回一个Promise,它将在下载所有URL时解析,并在其中任何一个失败时拒绝。
创建zip文件
现在我已经把所有的内容都下载到内存中了。正如我上面提到的,下载的内容被存储为Blob。下一步是使用这些Blob数据创建一个压缩文件。
import JsZip from 'jszip'; import FileSaver from 'file-saver'; const exportZip = blobs => { const zip = JsZip(); blobs.forEach((blob, i) => { zip.file(`file-${i}.csv`, blob); }); zip.generateAsync({type: 'blob'}).then(zipFile => { const currentDate = new Date().getTime(); const fileName = `combined-${currentDate}.zip`; return FileSaver.saveAs(zipFile, fileName); }); }
最终代码
让我们在这里完成我为此完成的所有代码。
import Promise from 'bluebird'; import JsZip from 'jszip'; import FileSaver from 'file-saver'; const download = url => { return fetch(url).then(resp => resp.blob()); }; const downloadByGroup = (urls, files_per_group=5) => { return Promise.map( urls, async url => { return await download(url); }, {concurrency: files_per_group} ); } const exportZip = blobs => { const zip = JsZip(); blobs.forEach((blob, i) => { zip.file(`file-${i}.csv`, blob); }); zip.generateAsync({type: 'blob'}).then(zipFile => { const currentDate = new Date().getTime(); const fileName = `combined-${currentDate}.zip`; return FileSaver.saveAs(zipFile, fileName); }); } const downloadAndZip = urls => { return downloadByGroup(urls, 5).then(exportZip); }
总结
利用客户端的功能有时对于减少后端的工作量和复杂性非常有用。
不要一次发送大量的请求。你会在前端和后端都遇到麻烦。相反,将作品分成小块。
介绍一些第三方库bluebird,jszip和file-saver。他们为我工作得很好,也可能对您有帮助。
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.