golang – 如何检查multipart.File的信息

huangapple go评论79阅读模式
英文:

golang - How to check multipart.File information

问题

当用户使用r.FormFile("file")上传文件时,您会得到一个multipart.File,一个multipart.FileHeader和一个error

我的问题是如何仅获取有关上传文件的信息。例如,它的大小,如果是图像的话,它的尺寸等等。

我真的不知道从哪里开始,所以任何帮助都将是很好的。

英文:

When a user uploads a file using r.FormFile("file") you get a multipart.File, a multipart.FileHeader and an error.

My question is how to just obtain information about the uploaded file . For example, its size, its dimensions if it's an image, and so on and so forth.

I have literally got no idea on where to start so any help would be great.

答案1

得分: 20

// 获取文件大小和MIME类型:

// 大小常量
const (
        MB = 1 << 20
)

type Sizer interface {
        Size() int64
}

func Sample(w http.ResponseWriter, r *http.Request) error {
        if err := r.ParseMultipartForm(5 * MB); err != nil {
                return err
        }

        // 限制上传大小
        r.Body = http.MaxBytesReader(w, r.Body, 5*MB) // 5 Mb

        //
        file, multipartFileHeader, err := r.FormFile("file")

        // 创建一个缓冲区来存储文件的头部
        fileHeader := make([]byte, 512)

        // 将头部复制到FileHeader缓冲区中
        if _, err := file.Read(fileHeader); err != nil {
                return err
        }

        // 将位置设置回起始位置
        if _, err := file.Seek(0, 0); err != nil {
                return err
        }

        log.Printf("Name: %#v\n", multipartFileHeader.Filename)
        log.Printf("Size: %#v\n", file.(Sizer).Size())
        log.Printf("MIME: %#v\n", http.DetectContentType(fileHeader))
}

示例输出:

2016/12/01 15:00:06 Name: "logo_35x30_black.png"
2016/12/01 15:00:06 Size: 18674
2016/12/01 15:00:06 MIME: "image/png"
英文:

To get the file size and MIME type:

// Size constants
const (
        MB = 1 &lt;&lt; 20
)

type Sizer interface {
        Size() int64
}

func Sample(w http.ResponseWriter, r *http.Request) error {
        if err := r.ParseMultipartForm(5 * MB); err != nil {
                return err
        }

        // Limit upload size
        r.Body = http.MaxBytesReader(w, r.Body, 5*MB) // 5 Mb

        //
        file, multipartFileHeader, err := r.FormFile(&quot;file&quot;)

        // Create a buffer to store the header of the file in
        fileHeader := make([]byte, 512)

        // Copy the headers into the FileHeader buffer
        if _, err := file.Read(fileHeader); err != nil {
                return err
        }

        // set position back to start.
        if _, err := file.Seek(0, 0); err != nil {
                return err
        }

        log.Printf(&quot;Name: %#v\n&quot;, multipartFileHeader.Filename)
        log.Printf(&quot;Size: %#v\n&quot;, file.(Sizer).Size())
        log.Printf(&quot;MIME: %#v\n&quot;, http.DetectContentType(fileHeader))
}

Sample output:

2016/12/01 15:00:06 Name: &quot;logo_35x30_black.png&quot;
2016/12/01 15:00:06 Size: 18674
2016/12/01 15:00:06 MIME: &quot;image/png&quot;

答案2

得分: 8

文件名和MIME类型可以从返回的multipart.FileHeader中获取。

大多数其他元数据将取决于文件类型。如果是图像文件,您应该能够使用标准库中的DecodeConfig函数,例如PNGJPEGGIF,以获取尺寸(和颜色模型)。

还有许多其他文件类型的Go库可用,它们将具有类似的功能。

编辑:golang-nuts邮件组上有一个很好的示例。

英文:

The file name and MIME type can be obtained from the returned multipart.FileHeader.

Most further meta-data will depend on the file type. If it's an image, you should be able to use the DecodeConfig functions in the standard library, for PNG, JPEG and GIF, to obtain the dimensions (and color model).

There are many Go libraries available for other file types as well, which will have similar functions.

EDIT: There's a good example on the golang-nuts mail group.

答案3

得分: 1

另一种我发现相当简单的测试方法是将测试资源放置在与包相对应的test_data目录中。在我的测试文件中,我通常创建一个帮助函数来创建*http.Request的实例,这样我就可以很容易地在multipart.File上运行表格测试(为了简洁起见,省略了错误检查)。

func createMockRequest(pathToFile string) *http.Request {
    file, err := os.Open(pathToFile)
    if err != nil {
        return nil
    }
    defer file.Close()

    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
    part, err := writer.CreateFormFile("file", filepath.Base(pathToFile))
    if err != nil {
        return nil
    }
    _, _ = io.Copy(part, file)

    err = writer.Close()
    if err != nil {
        return nil
    }
    // body是创建带有附加表单数据的新请求的唯一重要数据
    req, _ := http.NewRequest("POST", "", body)
    req.Header.Set("Content-Type", writer.FormDataContentType())
    return req
}
英文:

Another way I've found pretty simple for this type of testing is to place test assets in a test_data directory relative to the package. Within my test file I normally create a helper that creates an instance of *http.Request, which allows me to run table test pretty easily on multipart.File, (errors checking removed for brevity).

func createMockRequest(pathToFile string) *http.Request {
	file, err := os.Open(pathToFile)
	if err != nil {
		return nil
	}
	defer file.Close()

	body := &amp;bytes.Buffer{}
	writer := multipart.NewWriter(body)
	part, err := writer.CreateFormFile(&quot;file&quot;, filepath.Base(pathToFile))
	if err != nil {
		return nil
	}
	_, _ = io.Copy(part, file)

	err = writer.Close()
	if err != nil {
		return nil
	}
    // the body is the only important data for creating a new request with the form data attached
	req, _ := http.NewRequest(&quot;POST&quot;, &quot;&quot;, body)
	req.Header.Set(&quot;Content-Type&quot;, writer.FormDataContentType())
	return req
}

答案4

得分: 0

你可以从Content-Length头部获取文件的大致大小信息。这种方法不推荐使用,因为该头部可能会被更改。

更好的方法是使用ReadFrom方法:

clientFile, handler, err := r.FormFile("file") // r是*http.Request
var buff bytes.Buffer
fileSize, err := buff.ReadFrom(clientFile)
fmt.Println(fileSize) // 这将返回文件的大小。
英文:

You can get approximate information about the size of file from Content-Length header. This is not recommended, because this header can be changed.

A better way is to use ReadFrom method:

clientFile, handler, err := r.FormFile(&quot;file&quot;) // r is *http.Request
var buff bytes.Buffer
fileSize, err := buff.ReadFrom(clientFile)
fmt.Println(fileSize) // this will return you a file size.

huangapple
  • 本文由 发表于 2013年6月16日 11:04:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/17129797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定