Golang 文件上传 | 青训营笔记

560 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

Golang 文件上传

为了文章的整洁主要使用 Hertz 实现,其它框架可以查看这个网站是否有对应的代码:

文件上传 | Wen Flower 学习笔记

基本流程就是从请求的表单(DataForm)中获取 mulitpart.FileHeader 对象,然后通过 Open 方法获取实现了 Reader 接口的 mulitpart.File 对象,之后再进行对象存储上传或者文件保存操作

代码

package main

import (
    "context"

    "github.com/cloudwego/hertz/pkg/app"
    "github.com/cloudwego/hertz/pkg/app/server"
    "github.com/cloudwego/hertz/pkg/common/utils"
    "github.com/cloudwego/hertz/pkg/protocol/consts"
)

func main() {
    h := server.Default()

    h.POST("/upload", func(ctx context.Context, req *app.RequestContext) {
        header, err := req.FormFile("file")
        if err != nil {
            req.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
            return
        }
        
        filename := header.Filename

        log.Println(filename)

        // TODO 处理

        req.String(http.StatusOK, fmt.Sprintf("%s uploaded!", filename))
    })

    h.Spin()
}

将文件转为 byte 切片

可以通过创建一个 byte 切片,然后使用 Read 循环读取,也可以直接使用 io 包中提供的 Copy 方法,直接 Copy 到 bytes.Buffer 中,使用 Bytes() 获取整个文件的 byte 切片

file := header.Open()
defer file.Clone() // 这里可以处理一下关闭错误
buff := new(bytes.Buffer)
written, err := io.Copy(buff, file) // written 复制的字节数,err 复制过程中的错误
buff.Bytes()

文件类型验证

这里使用 github.com/h2non/filet…

// 使用文件头验证
head := make([]byte, 261)
_, err = file.Read(head)
if err != nil {
    return
}
// 这里检查是否是视频格式
if !filetype.IsVideo(head) {
    err = errno.AuthorizationFailedErr
    return
}

// 将偏移设置到文件开头
_, err = file.Seek(0, io.SeekStart)
if err != nil {
    return
}

支持的类型

  • Image
  • Video
  • Audio
  • Archive
  • Documents
  • Font
  • Application

详细的支持列表:Supported Types

所有的自带的支持类型都在 github.com/h2non/filet… 当中,这些类型都注册到了 filetype 中,使用 func Match(buf []byte) (types.Type, error) 函数会返回匹配的文件类型

match, err := filetype.Match(head)
if err != nil {
	// TODO Error Handler
}
if match == filetype.Unknown {
	// TODO Unknown Type
}
// TODO Other Type