Go web框架——Gin文件上传与下载
- 1. 文件上传
- 1.1 入门案例(单文件)
- 1.2 服务端保存文件的几种方式
- SaveUploadedFile
- Create+Copy
- 1.3 读取上传的文件
- 1.4 多文件上传
- 2. 文件下载
- 2.1 快速入门
- 2.2 前后端模式下的文件下载
- 2.3 中文乱码问题
1. 文件上传
1.1 入门案例(单文件)
func main() {
router := gin.Default()
// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
// 单位是字节, << 是左移预算符号,等价于 8 * 2^20
// gin对文件上传大小的默认值是32MB
// 1. 设置路由器的最大内存限制为8MB,用于处理multipart表单数据中的文件上传。
router.MaxMultipartMemory = 8 << 20 // 8 MiB
// 2. 定义一个路由处理函数
router.POST("/upload", func(c *gin.Context) {
// 单文件
// 3.通过c.FormFile函数获取HTTP请求上传的文件对象。
// 其中参数"file"是上传表单中文件类型的name属性值。
file, _ := c.FormFile("file")
// 使用log包打印上传的文件名。
log.Println(file.Filename)
// 4. 指定上传文件的目标完整路径
dst := "./" + file.Filename
// 5. 使用c.SaveUploadedFile函数保存文件到指定路径下。
c.SaveUploadedFile(file, dst)
// 6. 使用c.String函数向客户端响应上传成功信息。
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
router.Run(":8000")
}
1.2 服务端保存文件的几种方式
SaveUploadedFile
func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error
SaveUploadedFile函数用于将文件保存到指定的路径下。第一个参数是文件对象,第二个参数是保存文件的路径。
Create+Copy
func (c *Context) FormFile(name string) (*multipart.FileHeader, error)
FormFile函数用于获取上传的文件。它返回一个文件对象,其中包含了文件的元数据(名称、大小等)。我们可以使用这个文件对象去直接读取文件内容。
func main() {
router := gin.Default()
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
log.Println(file.Filename)
// 读取文件中的数据,返回文件对象
fileRead, _ := file.Open()
dst := "./" + file.Filename
// 创建一个文件
out, err := os.Create(dst)
if err != nil {
fmt.Println(err)
}
defer out.Close()
// 拷贝文件对象到out中
io.Copy(out, fileRead)
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
router.Run(":8000")
}
一样是使用Apifox调用,没有什么毛病~
1.3 读取上传的文件
func (c *Context) FormFile(name string) (*multipart.FileHeader, error)
FormFile函数用于获取上传的文件。它返回一个文件对象,其中包含了文件的元数据(名称、大小等)。我们可以使用这个文件对象去直接读取文件内容。
func main() {
router := gin.Default()
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
file, _ := c.FormFile("file")
// 读取文件中的数据,返回文件对象
fileRead, _ := file.Open()
defer fileRead.Close()
data, _ := io.ReadAll(fileRead)
fmt.Println(string(data))
c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
})
router.Run(":8000")
}
在这里我们可以根据文件的内容来判断是否需要保存到服务器中。
1.4 多文件上传
func (c *Context) MultipartForm() (*multipart.Form, error)
MultipartForm函数用于获取上传的表单数据。它返回一个包含了文件对象的表单对象。
func main() {
router := gin.Default()
// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["upload[]"] // 注意这里名字不要对不上了
for _, file := range files {
log.Println(file.Filename)
// 上传文件至指定目录
c.SaveUploadedFile(file, "./"+file.Filename)
}
c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
})
router.Run(":8000")
}
2. 文件下载
2.1 快速入门
直接响应一个路径下的文件
func main() {
router := gin.Default()
router.GET("/download", func(c *gin.Context) {
c.File("思考一个问题的四连问.txt")
})
router.Run(":8000")
}
然后,直接在游览器访问,就能下载到了!!
但是呐:
有些响应,比如图片,浏览器就会显示这个图片,而不是下载,所以我们需要使浏览器唤起下载行为
c.Header("Content-Type", "application/octet-stream") // 表示是文件流,唤起浏览器下载,一般设置了这个,就要设置文件名
c.Header("Content-Disposition", "attachment; filename="+"牛逼.png") // 用来指定下载下来的文件名
c.Header("Content-Transfer-Encoding", "binary") // 表示传输过程中的编码形式,乱码问题可能就是因为它
c.File("uploads/12.png")
完整代码:
func main() {
router := gin.Default()
router.GET("/download", func(c *gin.Context) {
c.Header("Content-Type", "application/octet-stream")
c.Header("Content-Disposition", "attachment; filename="+"牛逼.txt")
c.File("思考一个问题的四连问.txt")
})
router.Run(":8000")
}
这样再使用游览器,就直接下载了!!
2.2 前后端模式下的文件下载
如果是前后端模式下,后端就只需要响应一个文件数据
文件名和其他信息就写在请求头中
c.Header("fileName", "xxx.png")
c.Header("msg", "文件下载成功")
c.File("uploads/12.png")
前端写法
async downloadFile(row) {
this.$http({
method: 'post',
url: 'file/upload',
data:postData,
responseType: "blob"
}).then(res => {
const _res = res.data
let blob = new Blob([_res], {
type: 'application/png'
});
let downloadElement = document.createElement("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对象
})}
2.3 中文乱码问题
前后端模式下的文件下载,进程会出现中文乱码问题,我们需要进行修改,并且指定一些格式
后端
func Download(c *gin.Context) {
filename := url.QueryEscape("国家机密.txt")
// 可唤起浏览器下载
c.Header("Content-Disposition", "attachment; filename*=utf-8''"+filename) //
c.Header("fileName", filename)
c.File("uploads/国家机密.txt")
}
前端
async download() {
let res = await axios.get("/download", {headers: {responseType: "blob"}})
if (res.status === 200) {
let binaryData = [];
binaryData.push(res.data);
let url = window.URL.createObjectURL(new Blob(binaryData)); //表示一个指定的file对象或Blob对象
let a = document.createElement("a");
document.body.appendChild(a);
// 转码文件的标题
let filename = decodeURI(res.headers.filename)
// 调起文件下载
a.href = url;
a.download = filename; //命名下载名称
a.click(); //点击触发下载
window.URL.revokeObjectURL(url);
}
}
这就是简单的文件上传和下载啦~~