go基础库之比较两个文件

本文将向你展示如何快速确定两个文件是否相同。还将为你提供一种找到两者之间差异的方法。

比较两个文件

Golang 版本

1.12.1

前言

本文将向你展示如何快速确定两个文件是否相同。还将为你提供一种找到两者之间差异的方法。

实现

package main

import (
	"bufio"
	"crypto/md5"
	"fmt"
	"io"
	"os"
)

var data = []struct {
	name string
	cont string
	perm os.FileMode
}{
	{"test1.file", "Hello\nGolang is great", 0666},
	{"test2.file", "Hello\nGolang is great", 0666},
	{"test3.file", "Not matching\nGolang is great\nLast line",
		0666},
}

func main() {

	files := []*os.File{}
	for _, fData := range data {
		f, err := os.Create(fData.name)
		if err != nil {
			panic(err)
		}
		defer f.Close()
		_, err = io.WriteString(f, fData.cont)
		if err != nil {
			panic(err)
		}
		files = append(files, f)
	}

	// 通过校验和比较
	checksums := []string{}
	for _, f := range files {
		f.Seek(0, 0) // 重置文件的开头
		sum, err := getMD5SumString(f)
		if err != nil {
			panic(err)
		}
		checksums = append(checksums, sum)
	}

	fmt.Println("### 通过校验和比较 ###")
	compareCheckSum(checksums[0], checksums[1])
	compareCheckSum(checksums[0], checksums[2])

	fmt.Println("### 逐行比较 ###")
	files[0].Seek(0, 0)
	files[2].Seek(0, 0)
	compareFileByLine(files[0], files[2])

	// 清理
	for _, val := range data {
		os.Remove(val.name)
	}

}

func getMD5SumString(f *os.File) (string, error) {
	file1Sum := md5.New()
	_, err := io.Copy(file1Sum, f)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%X", file1Sum.Sum(nil)), nil
}

func compareCheckSum(sum1, sum2 string) {
	match := "match"
	if sum1 != sum2 {
		match = " does not match"
	}
	fmt.Printf("Sum: %s and Sum: %s %s\n", sum1, sum2, match)
}

func compareLines(line1, line2 string) {
	sign := "o"
	if line1 != line2 {
		sign = "x"
	}
	fmt.Printf("%s | %s | %s \n", sign, line1, line2)
}

func compareFileByLine(f1, f2 *os.File) {
	sc1 := bufio.NewScanner(f1)
	sc2 := bufio.NewScanner(f2)

	for {
		sc1Bool := sc1.Scan()
		sc2Bool := sc2.Scan()
		if !sc1Bool && !sc2Bool {
			break
		}
		compareLines(sc1.Text(), sc2.Text())
	}
}

$ go run main.go
### 通过校验和比较 ###
Sum: 5A07C1538087CD5B5C365DE52970E0A3 and Sum: 5A07C1538087CD5B5C365DE52970E0A3 match
Sum: 5A07C1538087CD5B5C365DE52970E0A3 and Sum: FED2EADA5D1D1EBF745DFDC7D1385E6C  does not match
### 逐行比较 ###
x | Hello | Not matching 
o | Golang is great | Golang is great 
x |  | Last line 

原理

两个文件的比较可以通过几种方式完成。 本文介绍了两种基本的方法。 第一个是通过创建文件的校验来比较整个文件。

第二种方法逐行比较文件(在本例中为字符串内容)。 如果不匹配,则标记x符号。 这与比较二进制内容的方式相同,但需要按字节块(字节切片)扫描文件。