file-io - go 中的文件读取和校验和。方法之间的差异

标签 file-io go sha512

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

示例:

第一个函数与 io/ioutil 一起使用并且适用于小文件。当我尝试复制一个大文件时,我的内存会受到爆炸,对于 1.5GB 的 iso,它会使用 3GB 的内存。

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 和示例后我不明白。 拥有可用的代码固然很好,但理解其工作原理远不止于此。

提前致谢!

最佳答案

以下代码不会执行您认为的操作。

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 示例中,当两个资源不相互依赖时,它们会同步使用。

关于file-io - go 中的文件读取和校验和。方法之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18430936/

相关文章:

go - 如何从 slice 中删除最后一个元素?

python - 如何在不使用 Flask-Security 的情况下验证它生成的哈希值?

php salt 我每个用户的密码 sha512 - 我这样做对吗?

c - 如何使用 C 从 bzip2 存档中提取所有数据?

c - fscanf 在应该返回 1 的时候始终返回 0

python - 如何修复 '' UnicodeDecodeError : 'charmap' codec can't decode byte 0x9d in position 29815: character maps to <undefined >'' ?

iphone - 像 C# 一样使用 SHA512 对密码字符串进行哈希处理

excel - Excel文件打开时的Matlab xlsread

go - go中所有类型的前置函数

戈朗 : How to handle and serve subdomains?