• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Golang 获取文件md5校验的方法以及效率对比

    近期有一个需求:获取多个文件 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[v0x0f]
    		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[v0x0f]
    		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的md5 hash计算操作
    • golang中字符串MD5生成方式总结
    上一篇:GoLang中生成UUID唯一标识的实现
    下一篇:Golang 实现获取当前函数名称和文件行号等操作
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

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