Complete guide to Python's os.lstat function covering file statistics, symbolic links, and practical examples.
Last modified April 11, 2025
This comprehensive guide explores Python’s os.lstat function, which retrieves file status without following symbolic links. We’ll cover stat structure, symbolic link handling, and practical file system examples.
The os.lstat function returns status information about a file without following symbolic links. It’s similar to os.stat but differs in symbolic link handling.
Key parameters: path (file/directory to examine). Returns a stat_result object containing file attributes like size, permissions, and timestamps.
This example demonstrates retrieving basic file information using os.lstat. We’ll show file size, modification time, and permissions in human-readable form.
basic_info.py
import os import time
file_path = “example.txt”
stats = os.lstat(file_path)
print(f"File: {file_path}") print(f"Size: {stats.st_size} bytes") print(f"Last modified: {time.ctime(stats.st_mtime)}") print(f"Permissions: {oct(stats.st_mode)[-3:]}") print(f"Owner UID: {stats.st_uid}") print(f"Group GID: {stats.st_gid}")
The code retrieves and displays basic file metadata. st_size gives file size, st_mtime shows modification time, and st_mode contains permission bits.
Note that os.lstat doesn’t follow symbolic links, unlike os.stat which would return info about the linked file instead of the link itself.
os.lstat can determine file types using the st_mode attribute combined with os.path’s file type checking functions. This example shows various checks.
file_type.py
import os import stat
path = “example”
stats = os.lstat(path)
print(f"Checking type of: {path}") print(f"Is regular file: {stat.S_ISREG(stats.st_mode)}") print(f"Is directory: {stat.S_ISDIR(stats.st_mode)}") print(f"Is symbolic link: {stat.S_ISLNK(stats.st_mode)}") print(f"Is FIFO/pipe: {stat.S_ISFIFO(stats.st_mode)}") print(f"Is block device: {stat.S_ISBLK(stats.st_mode)}") print(f"Is character device: {stat.S_ISCHR(stats.st_mode)}") print(f"Is socket: {stat.S_ISSOCK(stats.st_mode)}")
This code uses stat module constants to check various file types. Each S_IS* function returns True if the file matches that specific type.
For symbolic links, os.lstat will show them as links, while os.stat would show the type of the linked file.
This example demonstrates the difference between os.lstat and os.stat when working with symbolic links. We’ll create a link and examine both functions.
symlink_diff.py
import os
with open(“target.txt”, “w”) as f: f.write(“Original content”)
os.symlink(“target.txt”, “link.txt”)
link_stats = os.lstat(“link.txt”) target_stats = os.stat(“link.txt”)
print(“Symbolic link info (lstat):”) print(f"Size: {link_stats.st_size}") print(f"Is link: {os.path.islink(’link.txt’)}")
print("\nTarget file info (stat):") print(f"Size: {target_stats.st_size}") print(f"Is link: {os.path.islink(’target.txt’)}")
The output shows os.lstat returns info about the symbolic link itself (small size), while os.stat follows the link to return info about the target file.
This distinction is crucial when working with symbolic links in Python file operations.
os.lstat provides three timestamp values: st_atime (access), st_mtime (modification), and st_ctime (creation/change). This example shows all three.
timestamps.py
import os import time
file_path = “timestamp_example.txt”
with open(file_path, “w”) as f: f.write(“Initial content”) stats = os.lstat(file_path)
print(“Initial timestamps:”) print(f"Access: {time.ctime(stats.st_atime)}") print(f"Modification: {time.ctime(stats.st_mtime)}") print(f"Change: {time.ctime(stats.st_ctime)}")
time.sleep(1) with open(file_path, “a”) as f: f.write("\nAdditional content") new_stats = os.lstat(file_path)
print("\nAfter modification:") print(f"Access: {time.ctime(new_stats.st_atime)}") print(f"Modification: {time.ctime(new_stats.st_mtime)}") print(f"Change: {time.ctime(new_stats.st_ctime)}")
The example shows how different operations affect file timestamps. Writing to a file updates both mtime and ctime, while atime tracks last access.
Note: st_ctime has different meanings on Unix (metadata change) and Windows (creation time).
This example demonstrates how to interpret and modify file permissions using information from os.lstat and the stat module constants.
permissions.py
import os import stat
file_path = “permission_test.txt”
with open(file_path, “w”) as f: f.write(“Permission test”) stats = os.lstat(file_path)
print(f"Current permissions: {oct(stats.st_mode)[-3:]}")
print("\nPermission checks:") print(f"Owner readable: {bool(stats.st_mode & stat.S_IRUSR)}") print(f"Owner writable: {bool(stats.st_mode & stat.S_IWUSR)}") print(f"Owner executable: {bool(stats.st_mode & stat.S_IXUSR)}") print(f"Group writable: {bool(stats.st_mode & stat.S_IWGRP)}") print(f"Others executable: {bool(stats.st_mode & stat.S_IXOTH)}")
os.chmod(file_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP) new_stats = os.lstat(file_path) print(f"\nNew permissions: {oct(new_stats.st_mode)[-3:]}")
The code shows how to check individual permission bits using bitwise AND operations with stat module constants. It then demonstrates changing permissions with os.chmod.
Understanding these permission bits is essential for secure file handling in Python applications.
This example uses os.lstat to compare two files by their device/inode numbers, which is more reliable than comparing paths for detecting identical files.
file_comparison.py
import os
def are_same_file(file1, file2): try: stat1 = os.lstat(file1) stat2 = os.lstat(file2) return (stat1.st_dev == stat2.st_dev and stat1.st_ino == stat2.st_ino) except FileNotFoundError: return False
file_a = “file1.txt” file_b = “file2.txt” file_c = “file1.txt” # Hard link to file_a
with open(file_a, “w”) as f: f.write(“Content”) os.link(file_a, file_c) # Create hard link with open(file_b, “w”) as f: f.write(“Content”)
print(f"Same file (a vs b): {are_same_file(file_a, file_b)}") print(f"Same file (a vs c): {are_same_file(file_a, file_c)}") print(f"Same file (b vs c): {are_same_file(file_b, file_c)}")
The function compares device (st_dev) and inode (st_ino) numbers to determine if two paths reference the same physical file, even if they’re hard links.
This method works across different directory locations and with hard links, unlike simple path comparison.
Symbolic links: os.lstat doesn’t follow them, preventing symlink attacks
TOCTOU risks: File state can change between lstat and use
Permission checks: Always verify before sensitive operations
Error handling: Handle FileNotFoundError for missing files
Cross-platform: Some attributes differ between Unix and Windows
Use for links: Prefer lstat when working with symlinks
Combine with stat: Use both when full file info is needed
Check errors: Handle exceptions for missing files
Cache carefully: File info may change between checks
Document assumptions: Note when link vs target info is needed
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.