Python を使用すると、次のことができます。
equals = filecmp.cmp(file_old, file_new)
go言語でそれを行う組み込み関数はありますか? 私はそれをグーグルで検索しましたが、成功しませんでした。
パッケージでいくつかのハッシュ関数を使用することもできますhash/crc32
が、それは上記の Python コードよりも多くの作業です。
Python を使用すると、次のことができます。
equals = filecmp.cmp(file_old, file_new)
go言語でそれを行う組み込み関数はありますか? 私はそれをグーグルで検索しましたが、成功しませんでした。
パッケージでいくつかのハッシュ関数を使用することもできますhash/crc32
が、それは上記の Python コードよりも多くの作業です。
@captncraig の回答を完成させるために、2 つのファイルが同じかどうかを知りたい場合は、OS パッケージのSameFile(fi1, fi2 FileInfo)メソッドを使用できます。
SameFile は、fi1 と fi2 が同じファイルを記述しているかどうかを報告します。たとえば、Unix では、これは、下にある 2 つの構造体のデバイス フィールドと inode フィールドが同一であることを意味します。
それ以外の場合、ファイルの内容を確認したい場合は、メモリ内のファイル全体のロードを回避して、2 つのファイルを 1 行ずつチェックするソリューションを次に示します。
最初の試行: 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
}
}
}
その機能があなたが思っていることをするかどうかはわかりません。ドキュメントから、
浅いが与えられ、false でない限り、同一の os.stat() 署名を持つファイルは等しいと見なされます。
あなたの呼び出しは の署名のみを比較していos.stat
ます。これには以下のみが含まれます:
Go では、これら 3 つのことすべてをos.Stat
関数から学ぶことができます。これは、それらが文字通り同じファイルであるか、同じファイルへのシンボリックリンクであるか、またはそのファイルのコピーであることを示すだけです。
さらに詳しく知りたい場合は、両方のファイルを開いて比較できます (python バージョンは一度に 8k を読み取ります)。
crc または md5 を使用して両方のファイルをハッシュすることもできますが、長いファイルの先頭に違いがある場合は、早期に停止する必要があります。各リーダーから一度に数バイトを読み取り、 と比較することをお勧めしbytes.Compare
ます。
equalfileのようなパッケージを使用できます
メイン API:
func CompareFile(path1, path2 string) (bool, error)
ゴドック: https://godoc.org/github.com/udhos/equalfile
例:
package main
import (
"fmt"
"os"
"github.com/udhos/equalfile"
)
func main() {
if len(os.Args) != 3 {
fmt.Printf("usage: equal file1 file2\n")
os.Exit(2)
}
file1 := os.Args[1]
file2 := os.Args[2]
equal, err := equalfile.CompareFile(file1, file2)
if err != nil {
fmt.Printf("equal: error: %v\n", err)
os.Exit(3)
}
if equal {
fmt.Println("equal: files match")
os.Exit(0)
}
fmt.Println("equal: files differ")
os.Exit(1)
}
これがio.Reader
私が打ち出したものです。_, err := io.Copy(ioutil.Discard, newCompareReader(a, b))
2 つのストリームが同じコンテンツを共有していない場合、エラーが発生する可能性があります。この実装は、不要なデータのコピーを制限することでパフォーマンスを最適化します。
package main
import (
"bytes"
"errors"
"fmt"
"io"
)
type compareReader struct {
a io.Reader
b io.Reader
bBuf []byte // need buffer for comparing B's data with one that was read from A
}
func newCompareReader(a, b io.Reader) io.Reader {
return &compareReader{
a: a,
b: b,
}
}
func (c *compareReader) Read(p []byte) (int, error) {
if c.bBuf == nil {
// assuming p's len() stays the same, so we can optimize for both of their buffer
// sizes to be equal
c.bBuf = make([]byte, len(p))
}
// read only as much data as we can fit in both p and bBuf
readA, errA := c.a.Read(p[0:min(len(p), len(c.bBuf))])
if readA > 0 {
// bBuf is guaranteed to have at least readA space
if _, errB := io.ReadFull(c.b, c.bBuf[0:readA]); errB != nil { // docs: "EOF only if no bytes were read"
if errB == io.ErrUnexpectedEOF {
return readA, errors.New("compareReader: A had more data than B")
} else {
return readA, fmt.Errorf("compareReader: read error from B: %w", errB)
}
}
if !bytes.Equal(p[0:readA], c.bBuf[0:readA]) {
return readA, errors.New("compareReader: bytes not equal")
}
}
if errA == io.EOF {
// in happy case expecting EOF from B as well. might be extraneous call b/c we might've
// got it already from the for loop above, but it's easier to check here
readB, errB := c.b.Read(c.bBuf)
if readB > 0 {
return readA, errors.New("compareReader: B had more data than A")
}
if errB != io.EOF {
return readA, fmt.Errorf("compareReader: got EOF from A but not from B: %w", errB)
}
}
return readA, errA
}
標準的な方法は、それらを統計して os.SameFile を使用することです。
-- https://groups.google.com/g/golang-nuts/c/G-5D6agvz2Q/m/2jV_6j6LBgAJ
os.SameFile
Python とほぼ同じことを行う必要がありますfilecmp.cmp(f1, f2)
(つまりshallow=true
、stat によって取得されたファイル情報のみを比較することを意味します)。
func SameFile(fi1, fi2 FileInfo) bool
SameFile は、fi1 と fi2 が同じファイルを記述しているかどうかを報告します。たとえば、Unix では、これは、下にある 2 つの構造体のデバイス フィールドと inode フィールドが同一であることを意味します。他のシステムでは、決定はパス名に基づく場合があります。SameFile は、このパッケージの Stat によって返される結果にのみ適用されます。それ以外の場合は false を返します。
ただし、実際にファイルの内容を比較したい場合は、自分で行う必要があります。