82 lines
2 KiB
Diff
82 lines
2 KiB
Diff
7a8
|
|
> "bytes"
|
|
10a12
|
|
> "io"
|
|
489a492,568
|
|
> }
|
|
>
|
|
> // Decide if two files have the same contents or not.
|
|
> // chunkSize is the size of the blocks to scan by; pass 0 to get a sensible default.
|
|
> // *Follows* symlinks.
|
|
> //
|
|
> // May return an error if something else goes wrong; in this case, you should ignore the value of 'same'.
|
|
> //
|
|
> // derived from https://stackoverflow.com/a/30038571
|
|
> // under CC-BY-SA-4.0 by several contributors
|
|
> func FileCmp(file1, file2 string, chunkSize int) (same bool, err error) {
|
|
> if chunkSize == 0 {
|
|
> chunkSize = 4 * 1024
|
|
> }
|
|
>
|
|
> // shortcuts: check file metadata
|
|
> stat1, err := os.Stat(file1)
|
|
> if err != nil {
|
|
> return false, err
|
|
> }
|
|
>
|
|
> stat2, err := os.Stat(file2)
|
|
> if err != nil {
|
|
> return false, err
|
|
> }
|
|
>
|
|
> // are inputs are literally the same file?
|
|
> if os.SameFile(stat1, stat2) {
|
|
> return true, nil
|
|
> }
|
|
>
|
|
> // do inputs at least have the same size?
|
|
> if stat1.Size() != stat2.Size() {
|
|
> return false, nil
|
|
> }
|
|
>
|
|
> // long way: compare contents
|
|
> f1, err := os.Open(file1)
|
|
> if err != nil {
|
|
> return false, err
|
|
> }
|
|
> defer f1.Close()
|
|
>
|
|
> f2, err := os.Open(file2)
|
|
> if err != nil {
|
|
> return false, err
|
|
> }
|
|
> defer f2.Close()
|
|
>
|
|
> b1 := make([]byte, chunkSize)
|
|
> b2 := make([]byte, chunkSize)
|
|
> for {
|
|
> n1, err1 := io.ReadFull(f1, b1)
|
|
> n2, err2 := io.ReadFull(f2, b2)
|
|
>
|
|
> // https://pkg.go.dev/io#Reader
|
|
> // > Callers should always process the n > 0 bytes returned
|
|
> // > before considering the error err. Doing so correctly
|
|
> // > handles I/O errors that happen after reading some bytes
|
|
> // > and also both of the allowed EOF behaviors.
|
|
>
|
|
> if !bytes.Equal(b1[:n1], b2[:n2]) {
|
|
> return false, nil
|
|
> }
|
|
>
|
|
> if (err1 == io.EOF && err2 == io.EOF) || (err1 == io.ErrUnexpectedEOF && err2 == io.ErrUnexpectedEOF) {
|
|
> return true, nil
|
|
> }
|
|
>
|
|
> // some other error, like a dropped network connection or a bad transfer
|
|
> if err1 != nil {
|
|
> return false, err1
|
|
> }
|
|
> if err2 != nil {
|
|
> return false, err2
|
|
> }
|
|
> }
|