Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

Comparing Files and Directory Trees with filecmp

Compare file contents and directory trees with filecmp, understand shallow comparisons and caching, and separate mismatches from comparison errors.

Levels: Intermediate ~40 min read

Intermediate

Python’s filecmp module compares file contents and directory trees without launching an external diff program. Use it when a program needs to classify matching files, identify changed names, or summarize differences between two directory snapshots. It is not a replacement for pathlib when locating paths, shutil when copying them, or difflib when a human-readable text diff is needed.

Compare file contents deliberately

filecmp.cmp(first, second, shallow=False) compares the file contents when the files have different sizes or the comparison cannot be settled by the shallow shortcut. The default shallow=True treats files as equal when their stat signatures (file type, size, and modification time) match. That is a performance trade-off, not proof that their bytes are equal. For correctness-sensitive checks such as validating a copied file, choose shallow=False.

Interactive Runnable example
Edit

Ready to run.

Understand the shallow shortcut

Two files can have the same type, byte length, and modification time while containing different bytes. When those stat fields match, shallow=True may report a match without reading both contents. This behavior is useful for quick comparisons, but do not treat it as a content-integrity guarantee. Use controlled metadata in examples and shallow=False where the bytes must be checked.

Interactive Runnable example
Edit

Ready to run.

Compare a known set of names

filecmp.cmpfiles(left_dir, right_dir, common, shallow=False) compares the listed relative names in two directories. It returns three lists in this order: matches, mismatches, and errors. A missing or unreadable file belongs in errors; it is not the same as a readable file whose contents differ. Names in common may include subdirectory components.

Interactive Runnable example
Edit

Ready to run.

Inspect two directory trees with dircmp

filecmp.dircmp(left, right, shallow=False) builds a directory-comparison object. Its common, left_only, and right_only attributes describe names; common_files and common_dirs separate shared entries by kind; same_files and diff_files describe shared files that compare equal or different; funny_files and common_funny identify entries that could not be compared normally or have mismatched types. These attributes are computed lazily, so access only what the report needs.

Interactive Runnable example
Edit

Ready to run.

Follow directory comparisons into subdirectories

For shared subdirectories, dircmp.subdirs maps each directory name to another dircmp object. Inspect those children recursively when you need a tree-wide comparison. A directory comparison is a snapshot of filesystem state, not a synchronization plan: it does not copy, remove, or repair anything. If you act on its results later, remember that files may change between comparison and action.

Interactive Runnable example
Edit

Ready to run.

Use the comparison cache responsibly

filecmp caches prior comparisons to avoid repeating work. Cache entries are invalidated when the recorded stat information changes, but a quick rewrite can occur within the timestamp resolution of a filesystem. If a comparison immediately follows a write and the result must reflect the newest bytes, call filecmp.clear_cache() before comparing. Clearing the cache does not change files; it only discards saved comparison results.

Interactive Runnable example
Edit

Ready to run.

Ignore expected generated names

Pass ignore to dircmp when known generated entries should not affect the comparison, such as an application cache or a local build artifact. Ignoring a name is a reporting/comparison choice, not a deletion: filecmp does not modify either directory. Keep the ignore list narrow so unexpected differences remain visible.

Interactive Runnable example
Edit

Ready to run.

Choose the right comparison tool

Use filecmp when you need Boolean file comparisons or structural directory reports. Use difflib when people need to see which text lines differ. Use a cryptographic hash when the task requires a portable content fingerprint for data that may cross systems; a hash is still not a substitute for a threat model or authenticated provenance. For copying or updating files, use shutil or explicit application logic after deciding what a difference means.

Force content comparison

Complete the call so the comparison checks file contents rather than trusting matching stat signatures.

import filecmp
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as temporary:
    first = Path(temporary) / "one.txt"
    second = Path(temporary) / "two.txt"
    first.write_text("same", encoding="utf-8")
    second.write_text("same", encoding="utf-8")
    assert filecmp.cmp(first, second, ) is True
    print("content checked")

Separate differences from comparison errors

Choose the API that reports names as matches, mismatches, and errors.

import filecmp
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as temporary:
    left = Path(temporary) / "left"
    right = Path(temporary) / "right"
    left.mkdir()
    right.mkdir()
    (left / "a.txt").write_text("A", encoding="utf-8")
    (right / "a.txt").write_text("B", encoding="utf-8")
    matches, mismatches, errors = filecmp.(left, right, ["a.txt"], shallow=False)
    assert matches == [] and mismatches == ["a.txt"] and errors == []
    print(mismatches)

Read directory comparison results

Complete the attribute that lists common files whose contents differ.

import filecmp
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as temporary:
    left = Path(temporary) / "left"
    right = Path(temporary) / "right"
    left.mkdir(); right.mkdir()
    (left / "x.txt").write_text("left", encoding="utf-8")
    (right / "x.txt").write_text("right", encoding="utf-8")
    result = filecmp.dircmp(left, right, shallow=False)
    assert result. == ["x.txt"]
    print(result.diff_files)

Inspect child directory comparisons

Complete the expression to get the comparison object for a shared child directory named data.

import filecmp
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as temporary:
    left = Path(temporary) / "left" / "data"
    right = Path(temporary) / "right" / "data"
    left.mkdir(parents=True); right.mkdir(parents=True)
    (left / "item.txt").write_text("left", encoding="utf-8")
    (right / "item.txt").write_text("right", encoding="utf-8")
    comparison = filecmp.dircmp(left.parent, right.parent, shallow=False)
    nested = comparison.["data"]
    assert nested.diff_files == ["item.txt"]
    print(nested.diff_files)

Refresh cached comparisons after a rapid change

Choose the function that removes cached results before the next comparison.

import filecmp


assert callable(filecmp.clear_cache)
print("cache reset available")

Choose between an equality check and a line diff

Choose the standard-library module designed to show differences between text sequences.

from  import unified_diff
assert callable(unified_diff)
print("text diff helper imported")
Was this page helpful?

Mark this learning resource complete to track your learning progress.