G

[Golang]Gin框架 7.文件的上传与下载

RoLingG 2023-10-06

文件的上传与下载

单文件上传

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func main() {
    router := gin.Default()
    router.POST("/upload", func(c *gin.Context) {
        //只有form-data的形式才能上传文件,json也可以传文件,但是要以字节流的形式,和这个不太一样
        _file, _ := c.FormFile("file")
        fmt.Println(_file.Filename)
        //file.Size可限制用户上传文件的大小,以字节为单位
        fmt.Println(_file.Size % 1024)
        c.JSON(200, gin.H{"msg": "文件上传成功"})
        c.SaveUploadedFile(_file, "./upload/temp.png")
    })

    router.Run(":80")
}

——————————————————————————————————————————————

读取上传的文件(单文件)

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io"
)

func main() {
    router := gin.Default()
    router.POST("/upload", func(c *gin.Context) {
        file, _ := c.FormFile("file")
        //实际工作中要处理error,而不是用_替代
        readerFile, _ := file.Open()
        data, _ := io.ReadAll(readerFile)
        fmt.Println(string(data))
        c.JSON(200, gin.H{"msg": "上传成功"})
    })

    router.Run(":80")
}

这里我们可以用file.open()的功能读取用户上传的文件内容,然后去做一些事情,例如查看用户上传内容是否非法等。

——————————————————————————————————————————————

服务端保存文件的几种方式

SaveUploadedFile

c.SaveUploadedFile(file, address)

Create + Copy

file.Open的第一个返回值就是我们讲文件对象中的那个文件(只读的),我们可以使用这个去直接读取文件内容

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io"
    "os"
)

func main() {
    router := gin.Default()
    router.POST("/upload", func(c *gin.Context) {
        file, _ := c.FormFile("file")
        //实际工作中要处理error,而不是用_替代
        readerFile, _ := file.Open()
        writerFile, _ := os.Create("./upload/temp1.png")
        defer writerFile.Close()
        //意思就是创建一个temp1.png,将readerFile(用户上传的temp.png)给copy进temp1.png
        n, _ := io.Copy(writerFile, readerFile)
        fmt.Println(n)
        c.JSON(200, gin.H{"msg": "上传成功"})
    })

    router.Run(":80")
}

——————————————————————————————————————————————

多文件上传

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "io"
    "os"
)

func main() {
    router := gin.Default()
    //多文件上传
    router.POST("/uploads", func(c *gin.Context) {
        form, _ := c.MultipartForm()
        //File是一个map
        //upload[]是apipost里form-data里参数名填写的名字
        files, _ := form.File["upload[]"]
        for _, file := range files {
            c.SaveUploadedFile(file, "./upload/"+file.Filename)
        }
        c.JSON(200, gin.H{"mas": fmt.Sprintf("成功上传 %d 个文件", len(files))})
    })
    router.Run(":80")
}

——————————————————————————————————————————————

文件下载(单前端)

直接这样c.File("upload/temp1.png"),但会发现这样只能看到图片,不能下载(部分文件可以以这样的方式直接下载,但占少数)。

所以我们需要使浏览器唤起下载行为:

c.Header("Content-Type", "application/octet-stream")    //唤起浏览器下载文件流
c.Header("Content-Disposition", "attachment; filename="+"文件名.后缀")    // 用来指定下载下来的文件名。如果用了上面的唤起浏览器下载文件流,就一定要用这一个。(如果不加这个,老版本是我看教程是可以下载的,但是新版本我自己试了试貌似不行了)。这里的文件名是自己设的,设的什么下下来的文件名就是什么。
c.Header("Content-Transfer-Encoding", "binary")    // 表示传输过程中的编码形式,乱码问题可能就是因为它。(这个有时候有用,有时候又用不到,看具体情况,主要用于文件下载时重叠的情况)
c.File("upload/temp1.png")

小技巧:如果浏览器缓存了导致每次下载的东西都一样,但要是不一样的,就可以在网页f12,新定义一个时间戳new Date().getTime(),然后再url后面?+获得的时间戳即可。(这个方法好啊!)

——————————————————————————————————————————————

前后端模式下的文件下载

前后端模式下,后端就只需要响应头,去响应一个文件数据。

文件名和其他信息就写在请求头中。

如果出问题了,能直接将错误信息传递过来。因为c.File()是没有返回值的,所以错误了也不知道,只能自己写一个。

后端:

//响应头中设置文件的名字以及文件的响应信息(例如错误信息或者成功信息等)
c.Header("filename","xxx.后缀")
c.Header("msg":"文件下载成功")
c.File("upload/temp1.png")

前端:(这里前端就要写的复杂一些了,以下是前端下载的通用写法)

async downloadFile(row) {
   this.$http({
      method: 'post',
      url: 'file/upload',
      data:postData,
      responseType: "blob"    //responseType的blob是指XMLHttpRequest对象的一个属性,用于指定响应的数据类型为Blob对象(二进制大对象)。Blob对象是一种特殊的文件对象,可以存储二进制数据,如图像、音频、视频等。
   }).then(res => {
       const _res = res.data    //响应的data是后端c.JSON的data,code就是我们c.JSON里面的code(状态码)
      let blob = new Blob([_res], {
            type: 'application/png'
          });
      let downloadElement = document.createElement("a"); //创建a标签进行下载
      let href = window.URL.createObjectURL(blob); //创建下载的链接
      downloadElement.href = href;
      downloadElement.download = res.headers["fileName"]; //下载后文件名
      document.body.appendChild(downloadElement);
      downloadElement.click(); //点击下载
      document.body.removeChild(downloadElement); //下载完成移除元素
      window.URL.revokeObjectURL(href); //释放掉blob对象
    })}
//响应的时候判断响应
//要不然就是上面这种
//响应有时候不用data,就让它直接拿原信息就好。
//vue3里写法不一样,如果要用vue3看看理解理解就好
PREV
[Golang]Gin框架 6.验证器/校验器
NEXT
[Golang]Gin框架 8.返回第三方获取的数据

评论(0)

发布评论