Golang 获取文件md5校验的方法以及效率对比


Posted in Golang onMay 08, 2021

近期有一个需求:获取多个文件 md5 校验和判断是否存在重复文件,因为文件数量较多,有的文件还比较大,需要处理的文件还没有到位,我就考虑了一下效率的问题。

目前我已知的 Golang 中获取 md5 校验和的方法有两个

这里直接给出实现源码。

package main
import (
 "crypto/md5"
 "flag"
 "fmt"
 "io"
 "io/ioutil"
 "os"
)
var which = flag.Bool("which", true, "")
var path = flag.String("path", "", "")
var cnt = flag.Int("cnt", 100, "")
func aaa() {
 f, err := os.Open(*path)
 if err != nil {
  fmt.Println("Open", err)
  return
 }
 defer f.Close()
 body, err := ioutil.ReadAll(f)
 if err != nil {
  fmt.Println("ReadAll", err)
  return
 }
 md5.Sum(body)
 //fmt.Printf("%x\n", md5.Sum(body))
}
func bbb() {
 f, err := os.Open(*path)
 if err != nil {
  fmt.Println("Open", err)
  return
 }
 defer f.Close()
 md5hash := md5.New()
 if _, err := io.Copy(md5hash, f); err != nil {
  fmt.Println("Copy", err)
  return
 }
 md5hash.Sum(nil)
 //fmt.Printf("%x\n", md5hash.Sum(nil))
}
func main() {
 flag.Parse()
 for i := 0; i < *cnt; i++ {
  if *which {
   aaa()
  } else {
   bbb()
  }
 }
}

还有可供参考的获取 md5 校验和的 Shell 命令

md5 -- calculate a message-digest fingerprint (checksum) for a file
md5 [-pqrtx] [-s string] [file ...]

测试文件是公司项目的日志文件

banjakukutekiiMac:shell panshiqu$ ls -an | grep by
-rw-r--r--   1 501  20   7285957 11 17 16:14 by.out
banjakukutekiiMac:shell panshiqu$ cp by.out by2.out
banjakukutekiiMac:shell panshiqu$ cat by.out >> by2.out
banjakukutekiiMac:shell panshiqu$ ls -an | grep by
-rw-r--r--   1 501  20   7285957 11 17 16:14 by.out
-rw-r--r--   1 501  20  14571914 11 17 17:03 by2.out

下面效率展示

banjakukutekiiMac:shell panshiqu$ time ./gomd5 -cnt=1 -which=true -path="by.out"
real 0m0.027s
user 0m0.017s
sys 0m0.012s
banjakukutekiiMac:shell panshiqu$ time ./gomd5 -cnt=1 -which=true -path="by2.out"
real 0m0.048s
user 0m0.033s
sys 0m0.018s
banjakukutekiiMac:shell panshiqu$ time ./gomd5 -cnt=1 -which=false -path="by.out"
real 0m0.018s
user 0m0.012s
sys 0m0.004s
banjakukutekiiMac:shell panshiqu$ time ./gomd5 -cnt=1 -which=false -path="by2.out"
real 0m0.031s
user 0m0.024s
sys 0m0.005s
banjakukutekiiMac:shell panshiqu$ time md5 by.out
MD5 (by.out) = 9d79e19a00cef1ae1bb6518ca4adf9de
real 0m0.023s
user 0m0.019s
sys 0m0.006s
banjakukutekiiMac:shell panshiqu$ time md5 by2.out
MD5 (by2.out) = 0a029a460a20e8dcb00d032d6fab74c6
real 0m0.042s
user 0m0.037s
sys 0m0.009s

总结:

不管什么方法都会随着文件变大时间会变长,上面的例子大约都是2倍

io.Copy 方法效率最高,建议大家这样使用

补充:Go语言:md5计算方法的效率研究

研究了一下Go的md5计算方法,目前来看,效率最高运行最快的写法是调用md5.Sum()函数返回16字节checksum,然后把每个字节的高4位和低4位分别映射成16进制字符存到两个字节里,得到32字节,再转成字符串。

FastMD5较其它算法效率提高了至少46%以上。

const hextable = "0123456789abcdef" 
//作者: pengpengzhou
func FastMD5(str string) string {
	src := md5.Sum([]byte(str))
	var dst = make([]byte, 32)
	j := 0
	for _, v := range src {
		dst[j] = hextable[v>>4]
		dst[j+1] = hextable[v&0x0f]
		j += 2
	}
	return string(dst)
}

Go Test Benchmark测试结果:

goos: linux
goarch: amd64
pkg: example
BenchmarkFastMD5-4       5564898               205 ns/op
BenchmarkV1-4            3461698               379 ns/op
BenchmarkV2-4            2277235               516 ns/op
BenchmarkV3-4            2158122               527 ns/op
PASS
ok      example 6.440s

详细代码如下:

package main 
import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
)
 
const hextable = "0123456789abcdef"
 
func FastMD5(str string) string {
	src := md5.Sum([]byte(str))
	var dst = make([]byte, 32)
	j := 0
	for _, v := range src {
		dst[j] = hextable[v>>4]
		dst[j+1] = hextable[v&0x0f]
		j += 2
	}
	return string(dst)
}
 
func md5V1(str string) string {
	h := md5.New()
	h.Write([]byte(str))
	return hex.EncodeToString(h.Sum(nil))
}
 
func md5V2(str string) string {
	data := []byte(str)
	has := md5.Sum(data)
	md5str := fmt.Sprintf("%x", has)
	return md5str
}
 
func md5V3(str string) string {
	w := md5.New()
	io.WriteString(w, str)
	md5str := fmt.Sprintf("%x", w.Sum(nil))
	return md5str
}
 
func main() {
	str := "中文"
	fmt.Println(FastMD5(str))
	fmt.Println(md5V1(str))
	fmt.Println(md5V2(str))
	fmt.Println(md5V3(str))
}
package main 
import (
	"testing"
)
 
var str = "golang中文教程"
 
func BenchmarkFastMD5(b *testing.B) {
	for i := 0; i < b.N; i++ {
		FastMD5(str)
	}
}
 
func BenchmarkV1(b *testing.B) {
	for i := 0; i < b.N; i++ {
		md5V1(str)
	}
}
 
func BenchmarkV2(b *testing.B) {
	for i := 0; i < b.N; i++ {
		md5V2(str)
	}
}
 
func BenchmarkV3(b *testing.B) {
	for i := 0; i < b.N; i++ {
		md5V3(str)
	}
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。如有错误或未考虑完全的地方,望不吝赐教。

Golang 相关文章推荐
解决Golang中ResponseWriter的一个坑
Apr 27 Golang
golang通过递归遍历生成树状结构的操作
Apr 28 Golang
golang 接口嵌套实现复用的操作
Apr 29 Golang
Go使用协程交替打印字符
Apr 29 Golang
Golang中interface{}转为数组的操作
Apr 30 Golang
golang gopm get -g -v 无法获取第三方库的解决方案
May 05 Golang
解决golang 关于全局变量的坑
May 06 Golang
golang 实现并发求和
May 08 Golang
一文搞懂Golang 时间和日期相关函数
Dec 06 Golang
victoriaMetrics库布隆过滤器初始化及使用详解
Apr 05 Golang
golang操作rocketmq的示例代码
Apr 06 Golang
Go Grpc Gateway兼容HTTP协议文档自动生成网关
Jun 16 Golang
GoLang中生成UUID唯一标识的实现
May 08 #Golang
聊聊golang中多个defer的执行顺序
May 08 #Golang
Golang全局变量加锁的问题解决
golang 实现并发求和
May 08 #Golang
golang中的并发和并行
May 08 #Golang
关于golang高并发的实现与注意事项说明
May 08 #Golang
基于Golang 高并发问题的解决方案
May 08 #Golang
You might like
20个PHP常用类库小结
2011/09/11 PHP
PHP实现Soap通讯的方法
2014/11/03 PHP
php实现随机显示图片方法汇总
2015/05/21 PHP
PHP对象实例化单例方法
2017/01/19 PHP
php面向对象的用户登录身份验证
2017/06/08 PHP
基于jquery和svg实现超炫酷的动画特效
2014/12/09 Javascript
推荐10 款 SVG 动画的 JavaScript 库
2015/03/24 Javascript
深入理解Node.js中的进程管理
2017/03/13 Javascript
JavaScript阻止表单提交方法(附代码)
2017/08/15 Javascript
JS实现头条新闻的经典轮播图效果示例
2019/01/30 Javascript
详解Vue前端生产环境发布配置实战篇
2019/05/07 Javascript
解决vue-photo-preview 异步图片放大失效的问题
2020/07/29 Javascript
详细介绍Python语言中的按位运算符
2013/11/26 Python
python实现识别相似图片小结
2016/02/22 Python
python使用mysql数据库示例代码
2017/05/21 Python
python2.7安装图文教程
2018/03/13 Python
pandas DataFrame实现几列数据合并成为新的一列方法
2018/06/08 Python
Django框架的中的setting.py文件说明详解
2018/10/15 Python
Python使用Paramiko控制liunx第三方库
2020/05/20 Python
Python是什么 Python的用处
2020/05/26 Python
一篇文章带你搞定Ubuntu中打开Pycharm总是卡顿崩溃
2020/11/02 Python
python+excel接口自动化获取token并作为请求参数进行传参操作
2020/11/10 Python
浅析Python打包时包含静态文件处理方法
2021/01/15 Python
Boden美国官网:英伦原创时装品牌
2017/07/03 全球购物
瑜伽国际:Yoga International
2018/04/18 全球购物
互联网创业计划书写作技巧攻略
2014/03/23 职场文书
HR求职自荐信范文
2014/06/21 职场文书
国际贸易毕业生自荐书
2014/06/22 职场文书
学校社会实践活动总结
2014/07/03 职场文书
党的群众路线教育实践活动个人整改措施落实情况
2014/11/04 职场文书
授权委托书
2015/01/28 职场文书
三峡大坝导游词
2015/01/31 职场文书
团日活动总结格式
2015/05/11 职场文书
庆祝教师节主持词
2015/07/06 职场文书
Python破解极验滑动验证码详细步骤
2021/05/21 Python
一级电子管军用接收机测评
2022/04/05 无线电