首页 > 解决方案 > 使用很少的内存散列大文件

问题描述

我需要散列非常大的文件(>10TB 文件)。所以我决定每 MB 散列 128KB。我的想法是将文件分成 1MB 的块,并且只对每个块的前 128KB 进行哈希处理。

以下代码有效,但它使用了大量的内存,我不知道为什么......

func partialMD5Hash(filePath string) string {
    var blockSize int64 = 1024 * 1024
    var sampleSize int64 = 1024 * 128

    file, err := os.Open(filePath)
    if err != nil {
        return "ERROR"
    }
    defer file.Close()
    fileInfo, _ := file.Stat()
    fileSize := fileInfo.Size()

    hash := md5.New()

    var i int64
    for i = 0; i < fileSize / blockSize; i++ {
        sample := make([]byte, sampleSize)
        _, err = file.Read(sample)
        if err != nil {
            return "ERROR"
        }
        hash.Write(sample)

        _, err := file.Seek(blockSize-sampleSize, 1)
        if err != nil {
            return "ERROR"
        }
    }

    return hex.EncodeToString(hash.Sum(nil))
}

任何帮助将不胜感激!

标签: gomemoryhashmemory-leaks

解决方案


这种方法和程序存在几个问题。

如果要散列一个大文件,则必须散列所有文件。对文件的某些部分进行采样不会检测到对您未采样的部分的修改。

您正在为每次迭代分配一个新缓冲区。相反,在 for 循环之外分配一个缓冲区,然后重用它。

此外,您似乎忽略了实际读取的字节数。所以:

    block := make([]byte, blockSize)
    for {
        n, err = file.Read(block)
        if n>0 {
           hash.Write(sample[:n])
        }
        if err==io.EOF {
           break
        }
        if err != nil {
            return "ERROR"
        }
    }

但是,以下内容会更简洁:

io.Copy(hash,file)

推荐阅读