golang-echo框架上传文件

golang-echo框架上传文件

Echo 是一个 golang 的 web框架,官方描述为:

1
2
Echo
High performance, extensible, minimalist Go web framework

最近在学习文件上传功能,直接复制官方demo是正常可以运行的,但是自己添加了一些逻辑就不行了,
官方的一个简易demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package main

import (
"fmt"
"io"
"net/http"
"os"

"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)

func upload(c echo.Context) error {
// Read form fields
name := c.FormValue("name")
email := c.FormValue("email")

//-----------
// Read file
//-----------

// Source
file, err := c.FormFile("file")
if err != nil {
return err
}
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()

// Destination
dst, err := os.Create(file.Filename)
if err != nil {
return err
}
defer dst.Close()

// Copy
if _, err = io.Copy(dst, src); err != nil {
return err
}

return c.HTML(http.StatusOK, fmt.Sprintf("<p>File %s uploaded successfully with fields name=%s and email=%s.</p>", file.Filename, name, email))
}

func main() {
e := echo.New()

e.Use(middleware.Logger())
e.Use(middleware.Recover())

e.Static("/", "public")
e.POST("/upload", upload)

e.Logger.Fatal(e.Start(":1323"))
}

我自己的demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
file, err := c.FormFile("file")
if err != nil {
return err
}
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
md5, _ := util.FileMd5(src)
// Destination
dest := md5 + filepath.Ext(file.Filename)
dst, err := os.Create(file.Filename)
if err != nil {
return err
}
defer dst.Close()

// Copy
wr, err := io.Copy(dst, src)
if err != nil {
return err
}
fmt.Println(wr)
return c.HTML(http.StatusOK, fmt.Sprintf("<p>文件名字: %s,新名字:%s.</p>", file.Filename,dest))

md5 函数:

1
2
3
4
5
6
7
8
9
func FileMd5(file multipart.File) (string, error) {
h := md5.New()
_, err := io.Copy(h, file)
if err != nil {
return "", err
}
file.Seek(0, 0)
return hex.EncodeToString(h.Sum(nil)), nil
}

一步步地debug,发现最后 io.copy 之后,wr 写入数据量为0,而且只是增加了一个MD5地过程,发现有两次的 io.copy,猜测问题可能出在这里,

刚入门,后端一些知识不是很了解,只能寻求广大网友了,于是乎就找到办法了:

1
file.Seek()

知识点

io.copy 是一个很好用的方法, 它是将源复制到目标,并且是按默认的缓冲区32k循环操作的,不会将内容一次性全写入内存中,这样就能解决大文件的问题。(网上抄的)

file.Seek() 跳转到文本中的某处,并返回此处的偏移量,

原因

简单的来讲,文件整体读取完之后,读取位置就跑到的最后,然后再次,copy的时候,就会从上次的位置继续读取,那么肯定是读取不到的,所有要想继续读取,可以使用 file.Seek(0,0) 让文件指针移到开始位置,那么下次就会从开始位置读取了

作者

Fat Dong

发布于

2022-03-24

更新于

2022-03-24

许可协议