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 { name := c.FormValue("name") email := c.FormValue("email")
file, err := c.FormFile("file") if err != nil { return err } src, err := file.Open() if err != nil { return err } defer src.Close()
dst, err := os.Create(file.Filename) if err != nil { return err } defer dst.Close()
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)
dest := md5 + filepath.Ext(file.Filename) dst, err := os.Create(file.Filename) if err != nil { return err } defer dst.Close()
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
,猜测问题可能出在这里,
刚入门,后端一些知识不是很了解,只能寻求广大网友了,于是乎就找到办法了:
知识点
io.copy
是一个很好用的方法, 它是将源复制到目标,并且是按默认的缓冲区32k循环操作的,不会将内容一次性全写入内存中,这样就能解决大文件的问题。(网上抄的)
file.Seek()
跳转到文本中的某处,并返回此处的偏移量,
原因
简单的来讲,文件整体读取完之后,读取位置就跑到的最后,然后再次,copy的时候,就会从上次的位置继续读取,那么肯定是读取不到的,所有要想继续读取,可以使用 file.Seek(0,0)
让文件指针移到开始位置,那么下次就会从开始位置读取了