我正在尝试编写一个基于 md5 校验和检查文件重复项的程序。不太确定我是否遗漏了一些东西,但是这个读取 XCode 安装程序应用程序(它有大约 8GB)的功能使用了 16GB 的 RAM
func search() {
unique := make(map[string]string)
files, err := ioutil.ReadDir(".")
if err != nil {
log.Println(err)
}
for _, file := range files {
fileName := file.Name()
fmt.Println("CHECKING:", fileName)
fi, err := os.Stat(fileName)
if err != nil {
fmt.Println(err)
continue
}
if fi.Mode().IsRegular() {
data, err := ioutil.ReadFile(fileName)
if err != nil {
fmt.Println(err)
continue
}
sum := md5.Sum(data)
hexDigest := hex.EncodeToString(sum[:])
if _, ok := unique[hexDigest]; ok == false {
unique[hexDigest] = fileName
} else {
fmt.Println("DUPLICATE:", fileName)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
根据我的调试,问题在于文件读取是否有更好的方法来做到这一点?谢谢
Golang 文档中有一个示例,涵盖了您的情况。
package main
import (
"crypto/md5"
"fmt"
"io"
"log"
"os"
)
func main() {
f, err := os.Open("file.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
h := md5.New()
if _, err := io.Copy(h, f); err != nil {
log.Fatal(err)
}
fmt.Printf("%x", h.Sum(nil))
}
Run Code Online (Sandbox Code Playgroud)
对于您的情况,只需确保关闭循环中的文件而不是推迟它们。或者将逻辑放入函数中。
听起来 16GB RAM 是你的问题,而不是速度本身。
不要使用 ReadFile 将整个文件读入变量;io.Copy 从 Open 为您提供的 Reader 提供给 hash/md5 提供的 Writer(md5.New返回一个hash.Hash,其中嵌入了一个 io.Writer )。一次只复制一点点,而不是将所有文件拉入 RAM。
这是一个在 Go 中很多地方都很有用的技巧;text/template、compress/gzip、等包net/http按照读者和作者的方式工作。有了它们,您通常不需要创建巨大的[]bytes 或strings;您可以将 I/O 接口相互连接起来,让它们为您传递内容片段。在垃圾收集语言中,节省内存往往也会节省 CPU 工作。