Tidy Desk Digital ยท Free guides

Comparing File Contents in Python

Check whether a recovered file contains the same bytes as the original. Matching filenames and sizes are not enough; this program compares the contents without changing either file.

You'll need Python 3, a plain-text editor and a command window. No extra packages are required.

1. Prepare three files

Save Original.txt with this line, followed by a line ending:

Version A

Copy it to Recovered.txt, then create Changed.txt with Version B instead. Use files you can discard for the exercise.

A byte is a small unit of stored data. Our program compares those units directly, so it can check binary files as well as text without translating their contents.

2. Save the program

Save this as CompareFiles.py:

import os as Os
import stat as Stat
import sys as Sys


def CompareFiles(OriginalPath, CandidatePath):
    with open(OriginalPath, "rb") as Original:
        if not Stat.S_ISREG(Os.fstat(Original.fileno()).st_mode):
            raise ValueError("original must be a regular file")
        with open(CandidatePath, "rb") as Candidate:
            if not Stat.S_ISREG(Os.fstat(Candidate.fileno()).st_mode):
                raise ValueError("candidate must be a regular file")
            Total = 0
            while True:
                OriginalBlock = Original.read(65536)
                CandidateBlock = Candidate.read(65536)
                if OriginalBlock != CandidateBlock:
                    return False, Total
                if not OriginalBlock:
                    return True, Total
                Total += len(OriginalBlock)


def Main():
    if len(Sys.argv) != 3:
        print("Usage: python3 CompareFiles.py original-file candidate-file", file=Sys.stderr)
        return 2
    try:
        Same, Total = CompareFiles(Sys.argv[1], Sys.argv[2])
    except (OSError, ValueError) as Problem:
        print(f"Comparison stopped: {Problem}", file=Sys.stderr)
        return 2
    if Same:
        print(f"Identical: {Total} bytes.")
        return 0
    print("Different content.")
    return 1


if __name__ == "__main__":
    Sys.exit(Main())

Opening each input in rb reads stored bytes without translating them. The with blocks close the files when the work finishes or an error occurs.

The loop reads up to 65,536 bytes from each side and compares the blocks. It stops at a difference, or prints the total when both files end together. Line endings, one extra byte or a different way of storing text characters as bytes can all change the result.

Os.fstat gets information about the opened file and Stat.S_ISREG checks it is a regular file, such as a saved document. Use known regular files: opening a special file can block before that check runs.

3. Run the comparison

Open a command window in your folder and run:

python3 CompareFiles.py Original.txt Recovered.txt
python3 CompareFiles.py Original.txt Changed.txt
python3 CompareFiles.py Original.txt Missing.txt

Use your installation's Python 3 command if it is not named python3. An original containing Version A and one line-feed byte gives this result for its copy:

Identical: 10 bytes.

Your count may differ if the editor uses another line ending. Copying the original still gives an identical case. The changed file gives:

Different content.

The missing file produces an error beginning Comparison stopped:. Its exact wording depends on your system.

The exit code, a small result number another script can check, is 0 for identical contents, 1 for different contents and 2 when a command or read error stops the check. An error is not a content-difference result.

4. Try a less obvious difference

Equal sizes do not prove equal contents. Save this as MakeCases.py in your practice folder:

from pathlib import Path


Path("SameSizeA.txt").write_bytes(b"abc")
Path("SameSizeB.txt").write_bytes(b"xyz")
Path("EmptyA.txt").write_bytes(b"")
Path("EmptyB.txt").write_bytes(b"")

It creates or replaces these four files, so use a folder without files you need to keep. Run:

python3 MakeCases.py
python3 CompareFiles.py SameSizeA.txt SameSizeB.txt

Both inputs contain three bytes, but the output is Different content. and the exit code is 1. Now compare the empty pair:

python3 CompareFiles.py EmptyA.txt EmptyB.txt

The output is Identical: 0 bytes. and the exit code is 0. The setup writes explicit bytes, so no editor-added line ending can change these cases.

Passing the same path twice can give a match, but does not check a recovered copy. Make sure the candidate path points to the copy you intended.

The program passed 21 checks covering text, binary data, empty files, block boundaries, later differences, line endings and errors. Tested inputs remained unchanged.

After a byte match, open or import the file in its intended application when that matters. Matching contents does not prove the original was correct or the backup source trustworthy.

Use files that will not change during reading. The program does not lock them or make frozen copies, and follows symbolic links, paths pointing to other files. Reading can also change a file's recorded last-access time on some systems. This program is not designed to preserve files as investigation evidence.

Save output under a separate report filename, not over either input: the command window can empty a file before Python opens it. The program reads in small blocks but has no file-size or time limit.

References

More free code guides