是否有更快的替代ioutil.ReadFile?

时间:2017-07-14 09:19:32

标签: go

我正在尝试根据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)
            }
        }
    }
}

根据我的调试,问题在于文件读取 有没有更好的方法来做到这一点? 感谢

2 个答案:

答案 0 :(得分:4)

Golang文档中有一个example,它涵盖了您的案例。

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))
}

对于您的情况,只需确保关闭循环中的文件而不是推迟它们。或者将逻辑放入函数中。

答案 1 :(得分:3)

听起来像16GB内存是你的问题,而不是速度本身。

不要使用ReadFile将整个文件读入变量;来自Reader的io.Copy,Open给你到hash / md5提供的Writer(md5.New返回一个hash.Hash,它嵌入了一个io.Writer)。它只能一次复制一点,而不是将所有文件都拉入RAM。

这在Go的很多地方都很有用;像text/templatecompress/gzipnet/http这样的软件包以读者和作者的方式工作。有了它们,您通常不需要创建巨大的[]bytestring s;您可以将I / O接口相互连接起来,让它们为您传递内容。在垃圾收集语言中,节省内存往往也可以节省CPU工作量。