go中的文件读取和校验和。方法之间的区别

最近我开始为 go 中的文件创建校验和。我的代码正在处理大小文件。我尝试了两种方法,第一种使用ioutil.ReadFile("filename"),第二种使用os.Open("filename").


例子:


第一个功能是处理io/ioutil小文件。当我尝试复制一个大文件时,我的 ram 会出现爆炸,对于 1.5GB 的 iso,它使用 3GB 的 ram。


func byteCopy(fileToCopy string) {

    file, err := ioutil.ReadFile(fileToCopy) //1.5GB file

    omg(err)                                 //error handling function

    ioutil.WriteFile("2.iso", file, 0777)

    os.Remove("2.iso")

}

更糟糕的是,当我想使用crypto/sha512和创建校验和时io/ioutil。它永远不会完成并中止,因为它耗尽了内存。


func ioutilHash() {

    file, _ := ioutil.ReadFile(iso)

    h := sha512.New()

    fmt.Printf("%x", h.Sum(file))

}

使用下面的功能时,一切正常。


func ioHash() {

    f, err := os.Open(iso) //iso is a big ~ 1.5tb file

    omg(err)               //error handling function

    defer f.Close()

    h := sha512.New()

    io.Copy(h, f)

    fmt.Printf("%x", h.Sum(nil))

}

我的问题:


为什么该ioutil.ReadFile()功能无法正常工作?1.5GB 的文件不应该填满我的 16GB 内存。我现在不知道去哪里看。有人可以解释这些方法之间的差异吗?我不明白阅读 go-doc 和示例。拥有可用的代码很好,但理解为什么它的工作远高于此。


绝地无双
浏览 231回答 2
2回答

缥缈止盈

下面的代码没有做你认为的那样。func ioutilHash() {    file, _ := ioutil.ReadFile(iso)    h := sha512.New()    fmt.Printf("%x", h.Sum(file))}这首先读取您的 1.5GB iso。正如 jnml 所指出的,它不断地制造越来越大的缓冲区来填充它。最后,总缓冲区大小不小于 1.5GB 且不大于 1.875GB(按当前实现)。但是,在那之后,您再创建另一个缓冲区!h.Sum(file)不散列文件。它将当前哈希附加到文件中!这可能会也可能不会导致另一个分配。真正的问题是您正在获取该文件,现在附加了散列,并用 %x 打印它。fmt 实际上是使用 jnml 指出的 ioutil.ReadAll 所使用的相同类型的方法进行预计算的。因此它不断分配越来越大的缓冲区来存储文件的十六进制。由于每个字母是 4 位,这意味着我们谈论的是不小于 3GB 的缓冲区,不大于 3.75GB。这意味着您的活动缓冲区可能有 5.625GB 大。将其与 GC 不完美且未删除所有中间缓冲区相结合,它很容易填满您的空间。编写该代码的正确方法是。func ioutilHash() {    file, _ := ioutil.ReadFile(iso)    h := sha512.New()    h.Write(file)    fmt.Printf("%x", h.Sum(nil))}这几乎没有分配的数量。底线是 ReadFile 很少是您想要使用的。IO 流(使用读取器和写入器)总是最好的选择。当你使用 io.Copy 时,你不仅分配的更少,而且你还同时散列和读取磁盘。在您的 ReadFile 示例中,这两个资源在彼此不依赖时同步使用。

Cats萌萌

ioutil.ReadFile工作正常。通过使用该功能来滥用系统资源来处理您知道很大的事情是您的错。ioutil.ReadFile是一个方便的文件帮助程序,您事先很确定它们会很小。像配置文件,大多数源代码文件等(实际上它正在优化文件 <= 1e9 bytes,但这是一个实现细节,而不是 API 合同的一部分。您的 1.5GB 文件强制它使用切片增长,从而分配超过在读取文件的过程中为您的数据提供一个大缓冲区。)即使你使用的其他方法os.File也不好。您绝对应该使用“bufio”包来顺序处理大文件,请参阅bufio.NewReader。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go