2

关于一个打包下载的需求

 1 year ago
source link: https://blog.huoding.com/2022/07/01/984
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关于一个打包下载的需求

发表于2022-07-01

前些天遇到一个「打包下载」的需求,在调研过程中走了一些弯路,本文记录一下。

比如说某网站有一个文件列表,用户点哪个就可以下载哪个,如果用户想下载多个,无非就是多点几次而已。于是需求来了:当用户想下载多个文件的时候,可以通过一次点击完成打包下载操作。

听起来似乎并不复杂,服务端可以把用户想要下载的文件打包成一个新文件,然后用户点一次就可以下载了,但是这样做有以下几个缺点:

  • 浪费了时间,多了创建新文件的流程。
  • 浪费了空间,同样的文件被多次存储。
  • 用户体验差,下载必须要等到新文件创建好才能开始。

不难得出结论:动态流式下载才是正解,同事提到 tar 可以搞定,于是研究一下:

shell> cat test_0.txt 
xxx
xxx
shell> cat test_1.txt 
yyy
yyy
shell> tar cf test.tar test_0.txt test_1.txt
shell> cat test.tar 
test_0.txt00006440...01014257504126011510 0ustar rootrootxxx
xxx
test_1.txt00006440...01014257504241011507 0ustar rootrootyyy
yyy

如上可见,tar 文件的格式非常简单,多个文件的内容从上到下依次排列,只不过每个文件内容的前面附加了一个头,其中保存了诸如文件名,权限之类的信息。

看上去用 tar 的话确实可以搞定动态流式下载,不过 tar 有个缺点,普通用户搞不清 tar 文件类型是什么东西,相比较而言,他们更乐于接受 zip 文件类型。

不过 zip 文件类型的格式可要比 tar 复杂,我从 wikipedia 找到下图:

zip

对于凡夫俗子的我来说,想要通过手撸 zip 格式来实现动态流式下载绝非易事,就在举棋不定之际,我突然发现 golang 的 zip 标准库已经实现了 Writer 接口,这就意味着,我们只要结合使用 zip.NewWriter 和 http.ResponseWriter 就能实现我们的目的:

package main

import (
	"archive/zip"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	http.HandleFunc("/test", test)
	http.ListenAndServe(":8080", nil)
}

func test(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/zip")
	w.Header().Set("Content-Disposition", "attachment; filename=test.zip")
	writer := zip.NewWriter(w)
	for i := 0; i < 2; i++ {
		name := fmt.Sprintf("test_%d.txt", i)
		srcFile, err := os.Open(name)
		if err != nil {
			panic(err)
		}
		defer srcFile.Close()
		dstFile, err := writer.Create(name)
		if err != nil {
			panic(err)
		}
		if _, err := io.Copy(dstFile, srcFile); err != nil {
			panic(err)
		}
	}
	writer.Close()
}

如上代码编译运行后,打开浏览器,执行 http://localhost:8080/test 即可看到效果。

此条目由老王发表在Technical分类目录,并贴了Golang标签。将固定链接加入收藏夹。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK