GO实现文件上传操作

 更新时间:2022年07月26日 08:35:08   作者:Rookie_Hang  
这篇文章主要为大家详细介绍了GO实现文件上传操作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了GO实现文件上传操作的具体代码,供大家参考,具体内容如下

由于需求中有文件上传这一个需求,在这里我们就学习一下go语言如何上传文件。本文主要通过表单的方式进行文件上传操作。主要有以下三步:

  • 表单中增加enctype属性
  • 服务端调用r.ParseMultipartForm,把上传的文件存储在内存和临时文件中
  • 使用r.FormFile获取文件句柄,然后对文件进行存储等处理。

1、表单操作

要使表单能够上传文件,首先第一步就要添加form的enctype属性进去,enctype属性有如下三种情况:

application/x-www-form-urlencoded   表示在发送前编码所有字符(默认)
multipart/form-data      不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain      空格转换为 "+" 加号,但不对特殊字符编码。

所以可以创建如下上传表单:

<html>
<head>
    <title>上传文件</title>
</head>
<body>
<form enctype="multipart/form-data" action="/upload" method="post">
  <input type="file" name="uploadfile" />
  <input type="hidden" name="token" value="{{.}}"/>
  <input type="submit" value="upload" />
</form>
</body>
</html>

2、服务端操作

在服务端只需要添加一个handlerFunc并完善相关功能即可:

// 处理/upload 逻辑
func upload(w http.ResponseWriter, r *http.Request) {
    //获取请求的方法
    fmt.Println("method:", r.Method)
    //GET的处理操作
    if r.Method == "GET" {
        crutime := time.Now().Unix()
        h := md5.New()
        io.WriteString(h, strconv.FormatInt(crutime, 10))
        token := fmt.Sprintf("%x", h.Sum(nil))

        t, _ := template.ParseFiles("upload.gtpl")
        t.Execute(w, token)
    } else {
        //设置内存大小
        r.ParseMultipartForm(32 << 20)
        //获取上传文件
        file, handler, err := r.FormFile("uploadfile")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        fmt.Fprintf(w, "%v", handler.Header)
        //创建上传目录
        os.Mkdir("./test", os.ModePerm)
        //创建上传文件
        f, err := os.Create("./test/" + handler.Filename)
        //f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666) // 此处假设当前目录下已存在test目录
        if err != nil {
            fmt.Println(err)
            return
        }
        defer f.Close()
        io.Copy(f, file)
    }
}

main()函数中记得添加http.HandleFunc("/upload", upload)即可。

通过http://127.0.0.1:9999/upload来测试文件上传。 截图

选择文件之后就会在当前目录下的test文件夹中成功上传文件。

3、流程解析

通过上面的代码可以看到,处理文件上传我们需要调用r.ParseMultipartForm,里面的参数表示maxMemory,调用ParseMultipartForm之后,上传的文件存储在maxMemory大小的内存里面,如果文件大小超过了maxMemory,那么剩下的部分将存储在系统的临时文件中。我们可以通过r.FormFile获取上面的文件句柄,然后实例中使用了io.Copy来存储文件。我们可以尝试使用看一下使用的相关原函数:

ParseMultipartForm函数如下:

func (r *Request) ParseMultipartForm(maxMemory int64) error {
    if r.MultipartForm == multipartByReader {
        return errors.New("http: multipart handled by MultipartReader")
    }
    if r.Form == nil {
        err := r.ParseForm()
        if err != nil {
            return err
        }
    }
    if r.MultipartForm != nil {
        return nil
    }

    mr, err := r.multipartReader(false)
    if err != nil {
        return err
    }

    f, err := mr.ReadForm(maxMemory)
    if err != nil {
        return err
    }

    if r.PostForm == nil {
        r.PostForm = make(url.Values)
    }
    for k, v := range f.Value {
        r.Form[k] = append(r.Form[k], v...)
        // r.PostForm should also be populated. See Issue 9305.
        r.PostForm[k] = append(r.PostForm[k], v...)
    }

    r.MultipartForm = f

    return nil
}

FormFile函数如下:

func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) {
    if r.MultipartForm == multipartByReader {
        return nil, nil, errors.New("http: multipart handled by MultipartReader")
    }
    if r.MultipartForm == nil {
        err := r.ParseMultipartForm(defaultMaxMemory)
        if err != nil {
            return nil, nil, err
        }
    }
    if r.MultipartForm != nil && r.MultipartForm.File != nil {
        if fhs := r.MultipartForm.File[key]; len(fhs) > 0 {
            f, err := fhs[0].Open()
            return f, fhs[0], err
        }
    }
    return nil, nil, ErrMissingFile
}

文件handlermultipart.FileHeader里面的结构体如下

// A FileHeader describes a file part of a multipart request.
type FileHeader struct {
    Filename string
    Header   textproto.MIMEHeader
    Size     int64

    content []byte
    tmpfile string
}

4、成功结果

浏览器端显示如下消息。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 详解如何热重启golang服务器

    详解如何热重启golang服务器

    这篇文章主要介绍了详解如何热重启golang服务器,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Golang 实现复制文件夹同时复制文件

    Golang 实现复制文件夹同时复制文件

    这篇文章主要介绍了Golang 实现复制文件夹同时复制文件,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Go来合并两个csv的实现示例

    Go来合并两个csv的实现示例

    本文主要介绍了Go来合并两个csv的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • go语言执行等待直到后台goroutine执行完成实例分析

    go语言执行等待直到后台goroutine执行完成实例分析

    这篇文章主要介绍了go语言执行等待直到后台goroutine执行完成的方法,实例分析了Go语言中WaitGroup的使用技巧,需要的朋友可以参考下
    2015-03-03
  • Go实现短url项目的方法示例

    Go实现短url项目的方法示例

    这篇文章主要介绍了Go实现短url项目的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • Go语言操作redis数据库的方法

    Go语言操作redis数据库的方法

    这篇文章主要介绍了Go语言操作redis数据库的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • 使用Go重试机制代码更可靠

    使用Go重试机制代码更可靠

    这篇文章主要为大家介绍了使用Go重试机制的使用,使你的代码更加可靠,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 简单四步快速集成go环境变量

    简单四步快速集成go环境变量

    这篇文章主要为大家介绍了快速集成go环境变量的简单四个步骤详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Gin框架中的PostForm用法及说明

    Gin框架中的PostForm用法及说明

    这篇文章主要介绍了Gin框架中的PostForm用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • 在 Golang 中实现一个简单的Http中间件过程详解

    在 Golang 中实现一个简单的Http中间件过程详解

    本文在go web中简单的实现了中间件的机制,这样带来的好处也是显而易见的,当然社区也有一些成熟的 middleware 组件,包括 Gin 一些Web框架中也包含了 middleware 相关的功能,具体内容详情跟随小编一起看看吧
    2021-07-07

最新评论