我正在编写Web服务器。
在其中一个页面上,用户可以上传文件。
我希望能够处理zip文件。
在archive/zip
包中,我只看到两个允许我从zip存档中读取的函数:
func OpenReader(name string) (*ReadCloser, error)
func NewReader(r io.ReaderAt, size int64) (*Reader, error)
我想避免从磁盘写回来,
如果我想使用第二个函数,我需要在调用函数之前知道上传文件的大小。
问题
我将把问题分成两部分:
阅读通过标准multipart/form-data
html表单上传的zip文件的解压缩内容的惯用方法是什么?
如何获取通过html表单上传的文件的实际大小?
func(req *http.Request) {
f, h, err := req.FormFile("fileTag")
if err != nil {
panic(err)
}
var fileSize int = ??
unzipper, err := zip.NewReader(f, fileSize)
}
答案 0 :(得分:3)
您可以在FormFile Header中查找文件大小(MIMEHEader)。
h.Header.Get("Content-Length")
如果文件没有内容长度,您可以先将其读入缓冲区以获得大小。
var buff bytes.Buffer
fileSize, err := buff.ReadFrom(f)
其他选项是在你的答案中找到最终目的,或者从界面中获取具体的阅读器。如果多部分文件在内存中,它将是*io.SectionReader
,如果它被写入临时文件,则为*os.File
:
switch f := f.(type) {
case *io.SectionReader:
fileSize = r.Size()
case *os.File:
if s, err := f.Stat(); err == nil {
fileSize = s.Size()
}
}
答案 1 :(得分:2)
我发现这是一种获得尺寸的方法:
func(req *http.Request) {
f, h, err := req.FormFile("fileTag")
if err != nil {
panic(err)
}
fileSize, err := f.Seek(0, 2) //2 = from end
if err != nil {
panic(err)
}
_, err = f.Seek(0, 0)
if err != nil {
panic(err)
}
unzipper, err := zip.NewReader(f, fileSize)
}
我认为这种解决方案不是很优雅或惯用。
是不是有一些更清洁的方法来处理这种情况?
答案 2 :(得分:1)
我会使用内存缓冲区并确保限制文件的最大上传大小(~100MB?)
这是使用io.Copy
import (
"archive/zip"
"bytes"
"io"
"net/http"
)
func HttHandler(req *http.Request) {
f, _, err := req.FormFile("fileTag")
if err != nil {
panic(err)
}
buf := new(bytes.Buffer)
fileSize, err := io.Copy(buf, f)
if err != nil {
panic(err)
}
zip.NewReader(bytes.NewReader(buf.Bytes()), fileSize)
}