Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go http Request.FormFile:处理zip文件吗?_Go - Fatal编程技术网

Go http Request.FormFile:处理zip文件吗?

Go http Request.FormFile:处理zip文件吗?,go,Go,我正在用go编写一个web服务器 在其中一个页面上,用户可以上载文件 我想能够处理zip文件 在archive/zip软件包中,我只看到两个允许我读取zip存档的函数: func OpenReader(名称字符串)(*ReadCloser,错误) func新读卡器(r io.ReaderAt,大小int64)(*读卡器,错误) 我希望避免从磁盘写入和读取数据, 如果我想使用第二个函数,我需要在调用函数之前知道上传文件的大小 问题 我将问题分为两部分: 通过标准multipart/formdata

我正在用go编写一个web服务器

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

我想能够处理zip文件

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

  • func OpenReader(名称字符串)(*ReadCloser,错误)
  • func新读卡器(r io.ReaderAt,大小int64)(*读卡器,错误)
  • 我希望避免从磁盘写入和读取数据,
    如果我想使用第二个函数,我需要在调用函数之前知道上传文件的大小

    问题

    我将问题分为两部分:

  • 通过标准
    multipart/formdata
    html表单上传的zip文件的解压内容的惯用读取方式是什么

  • func(req *http.Request) {
        f, h, err := req.FormFile("fileTag")
        if err != nil {
             panic(err)
        }
        var fileSize int = ??
    
        unzipper, err := zip.NewReader(f, fileSize)
    }
    
  • 如何获得通过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)
    }
    

  • 您可以在FormFile中查找文件大小(这是一个)

    如果文件没有内容长度,可以先将其读入缓冲区以获得大小

    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()
        }
    }
    

    以下是我找到的一种获取尺寸的方法:

    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)
    }
    
    我觉得这个解决方案不是很优雅或地道


    没有更干净的方法来处理这种情况吗?

    我会使用内存缓冲区,并确保限制文件的最大上载大小(~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)
    
    }
    

    我的答案中的mime头解决方案不起作用吗?如果您缺少一个内容长度,这个解决方案实际上非常好,因为我不认为有一种方法可以在没有至少一个副本的情况下将其放入缓冲区。标题中没有
    content length
    。。。但是,
    Content Length
    将是客户端编写的头的值,对吗?是的,它是多部分形式的头(不是http请求头),因此必须由客户端发送。感谢SectionReader的建议。不幸的是,f可能是SectionReader,也可能是os.File。哦,是的,忘了这可以透明地放入临时文件。你也可以为os.File做一个类型转换,但我认为Seek解决方案实际上是最干净的,因为它一次覆盖了所有的基础。