Original link: https://blog.huoding.com/2022/07/01/984
A few days ago, I encountered a demand for “package download”, and I took some detours during the research process. This article records it.
For example, a website has a list of files, and users can download whichever they click. If the user wants to download more than one, it is nothing more than a few more clicks. So the demand comes: when users want to download multiple files, they can complete the package download operation with one click.
It doesn’t sound complicated. The server can package the file that the user wants to download into a new file, and then the user can download it with one click, but this has several disadvantages:
- Wasted time and more processes to create new files.
- Space is wasted and the same file is stored multiple times.
- The user experience is poor, and the download has to wait until the new file is created before it can start.
It is not difficult to come to the conclusion that dynamic streaming download is the correct solution. My colleague mentioned that tar can be done, so let’s study it:
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
As can be seen above, the format of the tar file is very simple. The contents of multiple files are arranged in order from top to bottom, except that a header is appended to the content of each file, which stores information such as file name and permissions.
It seems that using tar can indeed handle dynamic streaming downloads, but tar has a disadvantage. Ordinary users can’t figure out what the tar file type is. In comparison, they are more willing to accept the zip file type.
However, the format of the zip file type can be more complicated than tar. I found the following image from wikipedia :
For me as an ordinary person, it is not easy to realize dynamic streaming download through manual zip format. Just when I was indecisive, I suddenly found that golang’s zip standard library has implemented the Writer interface, which means, We just need to combine zip.NewWriter and http.ResponseWriter to achieve our purpose:
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() }
After the above code is compiled and run, open the browser and execute http://localhost:8080/test to see the effect.
This article is reproduced from: https://blog.huoding.com/2022/07/01/984
This site is for inclusion only, and the copyright belongs to the original author.