How to Find Duplicate Files by Size and Hash in Python
Recursively scan a directory, group files by size, then hash candidates to identify exact duplicate files.
Python code
40 linesimport hashlib
from pathlib import Path
def hash_file(path, chunk_size=8192):
hasher = hashlib.md5()
with open(path, 'rb') as f:
while chunk := f.read(chunk_size):
hasher.update(chunk)
return hasher.hexdigest()
def find_duplicates(directory):
size_map = {}
for path in Path(directory).rglob('*'):
if path.is_file():
size = path.stat().st_size
size_map.setdefault(size, []).append(path)
hash_map = {}
for size, paths in size_map.items():
if len(paths) > 1:
for path in paths:
file_hash = hash_file(path)
hash_map.setdefault((size, file_hash), []).append(path)
duplicates = []
for paths in hash_map.values():
if len(paths) > 1:
duplicates.append(paths)
return duplicates
if __name__ == "__main__":
test_dir = Path("/tmp/test_duplicates")
test_dir.mkdir(exist_ok=True)
(test_dir / "file1.txt").write_text("same content")
(test_dir / "file2.txt").write_text("same content")
(test_dir / "file3.txt").write_text("different")
result = find_duplicates(test_dir)
for group in result:
print([str(p) for p in group])
Output
['/tmp/test_duplicates/file1.txt', '/tmp/test_duplicates/file2.txt']
How it works
The script first groups all files by their size using a dictionary, which quickly narrows down potential duplicates. Only groups with more than one file are hashed, avoiding costly MD5 computation for unique sizes. The hash_file function reads files in chunks to handle large files without loading them entirely into memory. Files with the same size and identical hash are considered duplicates and grouped together. Using Path.rglob allows recursive traversal of subdirectories.
Common mistakes
- Hashing every file without pre-filtering by size, wasting I/O and CPU
- Ignoring symlinks, which may cause the same file to be counted twice
- Not handling permission errors when reading files
- Forgetting that files with zero size are all duplicates but hashing them is fine
Variations
- Use SHA-256 instead of MD5 for stronger collision resistance: `hashlib.sha256()`
- Return a dictionary mapping hash to list of paths instead of list of groups
Real-world use cases
- Cleaning up redundant copies in a photo library to free disk space.
- Identifying duplicate configuration files across multiple services in a repo.
- Detecting accidental file copies in a data pipeline before processing.
Sponsored
More from Files & data
- Append a Line to a Log File in Python easy
- Audit File Permissions Across a Project in Python easy
- Automatically Detect Corrupted Files Using SHA-256 Checksums in Python easy
- Automatically Highlight Data Validation Errors Inside Excel Files in Python easy
- Build a Command-Line To-Do List Application with Data Persistence in Python easy
- Build a File Index by Relative Path Hash Map in Python easy
Keep learning
Related tutorials and quizzes for this topic.