Python Basics: Hashing Files with SHA-256
A file digest helps detect whether bytes have changed. Python’s standard-library hashlib can calculate a SHA-256 digest without loading the entire file into memory.
Use Python 3.12 or newer on Linux. These scripts work only with data files created inside fresh temporary directories. Warning: each TemporaryDirectory context removes its directory and contents when it ends.
Calculate a file digest
Save as demo_hashlib_1.py:
from pathlib import Path
from tempfile import TemporaryDirectory
import hashlib
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
with path.open("xb") as file:
file.write(b"abc")
with path.open("rb") as file:
digest = hashlib.file_digest(file, "sha256").hexdigest()
print(digest)Run:
python3 demo_hashlib_1.pyOutput:
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015adfile_digest() was added in Python 3.11. Open the file in binary mode to hash the original bytes, including line endings. hexdigest() returns a 64-character hexadecimal string for SHA-256.
After file_digest(), don’t rely on the file object’s position or state for more reads. Close it, as the context manager does here, and reopen it if needed.
Feed a file to the hash in chunks
The explicit loop is useful when you need control over chunk size or want to count bytes as you read.
Save as demo_hashlib_2.py:
from pathlib import Path
from tempfile import TemporaryDirectory
import hashlib
with TemporaryDirectory() as directory:
path = Path(directory) / "sample.txt"
with path.open("xb") as file:
file.write(b"abc\n")
digest = hashlib.sha256()
total = 0
with path.open("rb") as file:
while chunk := file.read(65536):
digest.update(chunk)
total += len(chunk)
print("Bytes:", total)
print("Matches abc:", digest.hexdigest() == hashlib.sha256(b"abc").hexdigest())
print("Matches abc plus newline:", digest.digest() == hashlib.sha256(b"abc\n").digest())Run:
python3 demo_hashlib_2.pyOutput:
Bytes: 4
Matches abc: False
Matches abc plus newline: TrueThe newline changes the input. Multiple update() calls hash the concatenated bytes, so changing chunk size does not change the digest. digest() returns raw bytes; compare it with another raw digest, or compare two hexadecimal strings.
A matching digest does not prove who supplied a file. For a download, obtain the expected digest from a trusted source independent of an untrusted file. SHA-256 alone is also unsuitable for storing passwords. Avoid hashing files while another process is writing them.
References
Acknowledgements
This post was created with assistance from AI.