在go语言的开发中,当我们在操作下载或者上传文件对象时, 我们可以利用golang内置的io包中的 TeeReader函数特性,高效实时计算文件的md5值。 方法如下:
TeeReader高效计算文件md5示例
保存上传文件,并使用文件的md5签名.扩展名 作为保存文件名,再读取上传文件的同时计算文件md5签名
// 上传文件 使用文件md5签名.ext 作为文件名
func UploadFile(file *multipart.FileHeader) (string, error) {
f, err := file.Open() // 读取文件
if err != nil {
return "", fmt.Errorf("error reading multipart file: %v", err)
}
defer f.Close() // 创建文件 defer 关闭
// 计算文件md5 这里使用 TreeReader的特性在拷贝文件的同时 高效计算文件md5
md5 := md5.New()
treeReader := io.TeeReader(f, md5)
fmd5 := hex.EncodeToString(md5.Sum(nil)) // 获取上传文件的md5签名字符串
// 拼接目标文件 使用文件md5签名.ext 作为文件名
dstFile := filepath.Join("upload", fmd5+filepath.Ext(file.Filename) )
// 创建目标文件对象
dst, err := os.Create(dstFile)
if err != nil {
return "", fmt.Errorf("error creating dst file: %v", err)
}
defer dst.Close() // 创建文件 defer 关闭
// 从treeReader将文件拷贝到目标文件 dst
if _, err = io.Copy(dst, treeReader); err != nil {
return "", fmt.Errorf("error Copy file to destination: %v", err)
}
return dstFile, nil
}
TeeReader函数定义参考
// TeeReader returns a [Reader] that writes to w what it reads from r.
// All reads from r performed through it are matched with
// corresponding writes to w. There is no internal buffering -
// the write must complete before the read completes.
// Any error encountered while writing is reported as a read error.
func TeeReader(r Reader, w Writer) Reader {
return &teeReader{r, w}
}
type teeReader struct {
r Reader
w Writer
}
func (t *teeReader) Read(p []byte) (n int, err error) {
n, err = t.r.Read(p)
if n > 0 {
if n, err := t.w.Write(p[:n]); err != nil {
return n, err
}
}
return
}
总结:golang的io包中的这个TeeReader函数给我们提供了非常高效的文件操作的同时进行其他任务的接口,利用这个特性我们可以在保存文件的同时高效的计算文件的MD5, 也可以利用它来实时的显示文件操作进度条等。
更多使用方法参见 go语言内置io包中TreeReader函数的理解和使用示例_golang io.teereader-CSDN博客