http Request.FormFile:处理zip文件?

时间:2014-04-09 14:00:11

标签: go

我正在编写Web服务器。

在其中一个页面上,用户可以上传文件。

我希望能够处理zip文件。

archive/zip包中,我只看到两个允许我从zip存档中读取的函数:

  1. func OpenReader(name string) (*ReadCloser, error)
  2. func NewReader(r io.ReaderAt, size int64) (*Reader, error)
  3. 我想避免从磁盘写回来,
    如果我想使用第二个函数,我需要在调用函数之前知道上传文件的大小。

    问题

    我将把问题分成两部分:

    1. 阅读通过标准multipart/form-data html表单上传的zip文件的解压缩内容的惯用方法是什么?

    2. 如何获取通过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)
      }
      

3 个答案:

答案 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)

}