V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Visitor233
V2EX  ›  程序员

技术调研:云文件打包压缩下载至客户端,不在服务器落盘

  •  
  •   Visitor233 · 2020-11-24 09:05:02 +08:00 · 2301 次点击
    这是一个创建于 1220 天前的主题,其中的信息可能已经有所发展或是发生改变。

    RT,现在文件都是放在阿里云 OSS 存储。客户多选文件下载,肯定是打包成一个压缩包的。我现在是将文件流 stream 放在 dic 字典里,然后运行 ICSharpCode.SharpZipLib 这个包里的 Zip.ZipOutputStream 方法进行后续处理,将生成的 byte 放在 response 的 body 里。前端再下载响应内容。

    试了下,下载几张图片是正常的压缩包形式,解压正常。但下载内容包含一个 400 多 M 的视频时,服务就卡了 2 分钟,然后前端下了个空压缩包。

    请大佬们指点下,老实说我感觉这方法不靠谱。

    17 条回复    2020-11-24 10:44:30 +08:00
    kingfalse
        1
    kingfalse  
       2020-11-24 09:06:44 +08:00 via Android
    大文件不压缩呗?
    xuanbg
        2
    xuanbg  
       2020-11-24 09:09:23 +08:00
    落盘就是正常的文件下载,客户端可以断线续传,可以分段下载,可以……各种骚操作。不落盘你还能玩什么?多来几个大文件同时下载,别的不说,你服务器的内存就要爆掉了。
    imdong
        3
    imdong  
       2020-11-24 09:10:39 +08:00   ❤️ 1
    使用 JS 加载回来后在浏览器端进行打包处理?

    但是我不知道 zip 之类的压缩是否需要等所有文件都加载完毕后才能生成压缩文件的头部。

    如果有可以顺序加载的话,可以考虑客户端一边读取一边生成压缩包下载。
    xuanbg
        4
    xuanbg  
       2020-11-24 09:14:17 +08:00
    @imdong 没压缩完文件长度都不知道啊,怎么生成头部?
    imdong
        5
    imdong  
       2020-11-24 09:16:51 +08:00
    查了一下 zip 的包结构(不确定是否正确)

    ```
    [local file header + file data + data descriptor]{1,n} + central directory + end of central directory record

    [文件头+文件数据+数据描述符]{此处可重复 n 次}+核心目录+目录结束标识

    当压缩包中有多个文件时,就会有多个[文件头+文件数据+数据描述符]
    ```

    如果包结构是这样的话,应该是可以做到 边加载 边压缩 边输出下载。

    应该叫 流压缩?那九成九是已经有现成的轮子可以用(除非无法实现)。

    至于是在浏览器端处理还是在服务端处理,见仁见智吧。
    Visitor233
        6
    Visitor233  
    OP
       2020-11-24 09:17:37 +08:00
    @xuanbg 我也是这么觉得的,400M,我的小电脑就死了。
    @kingfalse 现在不确定用户的文件大小,而且项目赶,求稳。
    @imdong 涨知识了,之前在阿里文档中看到过一篇介绍边下载边解压的技术,可惜没提供代码
    imdong
        7
    imdong  
       2020-11-24 09:18:28 +08:00
    @xuanbg 如一楼所说,不压缩,只归档,我们应该是可以做到提前知道文件的一些已知信息如大小。
    wanguorui123
        8
    wanguorui123  
       2020-11-24 09:20:58 +08:00
    HTTP 实时返回压缩流,不要打包再下载
    Akkuman
        9
    Akkuman  
       2020-11-24 09:21:11 +08:00 via Android
    可以实现,golang 中就有类似的,打包的输出流写入 resp writer,不断 flush
    shuax
        10
    shuax  
       2020-11-24 09:21:19 +08:00
    搞 tar 格式,别压缩
    imdong
        11
    imdong  
       2020-11-24 09:27:17 +08:00
    https://stuk.github.io/jszip/documentation/examples/downloader.html

    看到这个 jszip 的库可以实现在客户端加载远程文件生成压缩文件输出到下载。

    但是这个似乎需要等所有的文件都加载完毕后才能压缩并输出下载,大文件可能会造成浏览器崩溃?

    应该有更佳实现,同步输出下载的,@Akkuman #9 证明这种方案是一定可行的。

    至于如何实现,抛针引线,楼主自己努力找一下吧。
    okaku
        12
    okaku  
       2020-11-24 09:37:10 +08:00
    这些可以在前端解决。zip 本身支持无压缩只归档。
    但是在前端无法实现从浏览器下载管理器中的断点续传。只能从 web 页面上断点续传。
    前端实现在对一些手机浏览器的兼容上有差异。
    Joyuce
        13
    Joyuce  
       2020-11-24 09:46:04 +08:00
    服务器打包上传 oss,给客户端链接,带宽压力不就在 oss 了
    Fred0410
        14
    Fred0410  
       2020-11-24 09:58:35 +08:00
    teambition 的网盘用的就是这个放方法
    wangritian
        15
    wangritian  
       2020-11-24 10:15:08 +08:00
    ecs 的流量很贵吧,给 oss 开 cdn,带宽峰值收费,下载 api 拆成 2 个,1 个接收文件列表、指定压缩包路径、异步打包、立即返回路径,此时界面可以显示“正在压缩...”,第 2 个循环访问 cdn 路径,直到成功下载或超时
    wunonglin
        16
    wunonglin  
       2020-11-24 10:37:26 +08:00
    oss 不是有打包的计算函数?直接用不就行了?
    forcecharlie
        17
    forcecharlie  
       2020-11-24 10:44:30 +08:00
    @imdong HTTP chunk 编码可以满足
    @xuanbg 如果使用 Golang 直接将 Zip 的输出流 io.Copy 到 http.ResponseWriter 内存消耗也比较低 实际上压缩都可以这么玩,就算是 tar.gz 也可以这样压缩解压输出到 HTTP 响应,并不需要占用很多的内存,但 CPU 反正不低,Git 代码托管平台存储库 archive 下载很多就是这个思路,当然其中涉及到缓存,即通过 io.MultiWriter 写入到磁盘和 Hash.

    C# 的则需要自己封装一下。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1015 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 19:31 · PVG 03:31 · LAX 12:31 · JFK 15:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.