如何比较golang中的两个文件?

rvi*_*nca 3 go file-comparison filecompare

使用Python我可以做下一个:

equals = filecmp.cmp(file_old, file_new)
Run Code Online (Sandbox Code Playgroud)

在go语言中是否有任何内置函数可以做到这一点?我用Google搜索但没有成功.

我可以在hash/crc32包中使用一些哈希函数,但这比上面的Python代码更有用.

Pit*_*ith 11

要完成@captncraig答案,如果您想知道这两个文件是否相同,可以使用OS软件包中的SameFile(fi1,fi2 FileInfo)方法.

SameFile报告fi1和fi2是否描述相同的文件.例如,在Unix上,这意味着两个底层结构的设备和inode字段是相同的;

否则,如果要检查文件内容,这里有一个解决方案,它逐行检查两个文件,避免加载内存中的整个文件.

首先尝试:https://play.golang.org/p/NlQZRrW1dT


编辑:按字节块读取,如果文件大小不同,则快速失败.https://play.golang.org/p/YyYWuCRJXV

const chunkSize = 64000

func deepCompare(file1, file2 string) bool {
    // Check file size ...

    f1, err := os.Open(file1)
    if err != nil {
        log.Fatal(err)
    }
    defer f1.Close()

    f2, err := os.Open(file2)
    if err != nil {
        log.Fatal(err)
    }
    defer f2.Close()

    for {
        b1 := make([]byte, chunkSize)
        _, err1 := f1.Read(b1)

        b2 := make([]byte, chunkSize)
        _, err2 := f2.Read(b2)

        if err1 != nil || err2 != nil {
            if err1 == io.EOF && err2 == io.EOF {
                return true
            } else if err1 == io.EOF || err2 == io.EOF {
                return false
            } else {
                log.Fatal(err1, err2)
            }
        }

        if !bytes.Equal(b1, b2) {
            return false
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么扫描仪的开销?这需要解析字节,寻找你不关心的行分隔符.它也可能无法达到您对二进制文件的期望.您可以将"块"读入一对合理大小的缓冲区,然后使用`bytes.Equal`(这是@captncraig建议的). (2认同)

cap*_*aig 9

我不确定该功能是否符合你的想法.从文档中,

除非给出浅并且为false,否则具有相同os.stat()签名的文件将被视为相同.

您的通话仅比较签字os.stat,其中仅包括:

  1. 文件模式
  2. 修改时间
  3. 尺寸

你可以从os.Stat函数中学习Go中的所有这三件事.这实际上只表明它们与同一文件或该文件的副本完全相同,或者是符号链接.

如果你想深入一点,你可以打开这两个文件并进行比较(python版本一次读取8k).

您可以使用crc或md5来散列两个文件,但如果在长文件的开头存在差异,则需要提前停止.我建议每次从每个阅读器读取一些字节数并与之比较bytes.Compare.


cha*_*sio 6

怎么样使用bytes.Equal

package main

import (
"fmt"
"io/ioutil"
"log"
"bytes"
)

func main() {
    // per comment, better to not read an entire file into memory
    // this is simply a trivial example.
    f1, err1 := ioutil.ReadFile("lines1.txt")

    if err1 != nil {
        log.Fatal(err1)
    }

    f2, err2 := ioutil.ReadFile("lines2.txt")

    if err2 != nil {
        log.Fatal(err2)
    }

    fmt.Println(bytes.Equal(f1, f2)) // Per comment, this is significantly more performant.
}
Run Code Online (Sandbox Code Playgroud)

  • 这篇文章有两个问题。1.您鼓励将所有数据加载到内存中。2. DeepEqual使用反射且速度较慢。使用字节更有意义。等于,如果不存在这样的功能,我建议使用for循环。 (3认同)