ZetCode

Python os.stat 函数

上次修改时间:2025 年 4 月 11 日

本篇综合指南探讨了 Python 的 os.stat 函数,该函数用于检索详细的文件系统元数据。我们将介绍 stat 结构属性、平台差异以及实际的文件信息示例。

基本定义

os.stat 函数返回一个 stat_result 对象,其中包含文件系统元数据。 它适用于所有平台上的文件和目录。

关键属性包括 st_mode(权限)、st_size(大小)、st_mtime(修改时间)。 可用的确切属性因操作系统而异。

获取基本文件信息

os.stat 最简单的用法是检索基本文件元数据,如大小和修改时间。 此示例显示了常见的可用属性。

basic_stats.py
import os
import time

file_path = "example.txt"
stats = os.stat(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"Last accessed: {time.ctime(stats.st_atime)}")
print(f"Created: {time.ctime(stats.st_ctime)}")
print(f"Mode: {oct(stats.st_mode)}")
print(f"Inode: {stats.st_ino}")

此代码检索并显示常见的文件属性。 请注意,st_ctime 在 Windows 上表示创建时间,但在类 Unix 系统上表示元数据更改时间。

st_mode 属性以八进制格式显示文件权限和类型。 我们将在后面的示例中更详细地探讨这一点。

检查文件类型

st_mode 属性包含文件类型信息,可以使用 stat 模块常量进行检查。 这有助于区分文件和目录。

file_type.py
import os
import stat

path = "example.txt"
stats = os.stat(path)

mode = stats.st_mode

if stat.S_ISREG(mode):
    print(f"{path} is a regular file")
elif stat.S_ISDIR(mode):
    print(f"{path} is a directory")
elif stat.S_ISLNK(mode):
    print(f"{path} is a symbolic link")
elif stat.S_ISSOCK(mode):
    print(f"{path} is a socket")
else:
    print(f"{path} is of unknown type")

此示例使用 stat 模块函数来确定文件类型。 每个函数都检查 st_mode 字段中的特定位以确定文件类型。

请注意,对于符号链接,os.stat 默认跟随它们。 使用 os.lstat 获取有关链接本身而不是其目标的信息。

检查文件权限

可以使用按位运算或 stat 模块常量从 st_mode 中提取文件权限。 此示例显示了这两种方法。

file_permissions.py
import os
import stat

file_path = "script.sh"
stats = os.stat(file_path)

mode = stats.st_mode

# Using bitwise operations
user_read = mode & stat.S_IRUSR
user_write = mode & stat.S_IWUSR
user_exec = mode & stat.S_IXUSR

print(f"Owner permissions:")
print(f"  Read: {'Yes' if user_read else 'No'}")
print(f"  Write: {'Yes' if user_write else 'No'}")
print(f"  Execute: {'Yes' if user_exec else 'No'}")

# Using stat module constants
print("\nUsing stat module:")
print(f"Readable by owner: {bool(mode & stat.S_IRUSR)}")
print(f"Writable by owner: {bool(mode & stat.S_IWUSR)}")
print(f"Executable by owner: {bool(mode & stat.S_IXUSR)}")

第一种方法使用按位 AND 检查特定的权限位。 第二种方法展示了更简洁的版本,直接使用 stat 常量。

可以按照相同的模式对组(S_IRGRP 等)和其他用户(S_IROTH 等)权限进行类似的检查。

处理文件时间

os.stat 提供三个与时间相关的属性:st_atime(访问时间)、st_mtime(修改时间)和 st_ctime(创建/元数据更改时间)。 此示例显示了如何使用它们。

file_times.py
import os
import time
from datetime import datetime

file_path = "document.txt"
stats = os.stat(file_path)

# Raw timestamp values
print(f"Access time (timestamp): {stats.st_atime}")
print(f"Modification time (timestamp): {stats.st_mtime}")
print(f"Metadata change time (timestamp): {stats.st_ctime}")

# Convert to readable format
print("\nFormatted times:")
print(f"Last accessed: {datetime.fromtimestamp(stats.st_atime)}")
print(f"Last modified: {datetime.fromtimestamp(stats.st_mtime)}")
print(f"Metadata changed: {datetime.fromtimestamp(stats.st_ctime)}")

# Time comparisons
now = time.time()
hours_since_mod = (now - stats.st_mtime) / 3600
print(f"\nModified {hours_since_mod:.1f} hours ago")

这演示了如何访问原始时间戳值并将它们转换为人类可读的格式。 它还显示了如何计算时间差。

请记住,st_ctime 在不同平台上的含义不同 - 在 Windows 上表示创建时间,在类 Unix 系统上表示元数据更改时间。

比较文件

st_ino(inode)和 st_dev(设备)属性可以唯一标识文件并检测硬链接。 此示例显示了文件比较技术。

file_comparison.py
import os

def are_same_file(path1, path2):
    stats1 = os.stat(path1)
    stats2 = os.stat(path2)
    
    return (stats1.st_ino == stats2.st_ino and 
            stats1.st_dev == stats2.st_dev)

file1 = "original.txt"
file2 = "hardlink.txt"
file3 = "copy.txt"

print(f"{file1} and {file2} same file: {are_same_file(file1, file2)}")
print(f"{file1} and {file3} same file: {are_same_file(file1, file3)}")

# Additional comparison by metadata
stats1 = os.stat(file1)
stats2 = os.stat(file3)

if (stats1.st_size == stats2.st_size and
    stats1.st_mtime == stats2.st_mtime):
    print("\nFiles have same size and modification time")
else:
    print("\nFiles differ in size or modification time")

are_same_file 函数通过比较 inode 和设备编号来检查两个路径是否指向同一物理文件。 这会检测硬链接。

第二个比较显示了如何检查文件是否具有相同的元数据,而不一定是相同的物理文件。

处理符号链接

os.stat 默认跟随符号链接。 使用 os.lstat 获取有关链接本身而不是其目标的信息。

symlink_stats.py
import os
import stat

# Create a symbolic link for demonstration
if not os.path.exists("target.txt"):
    with open("target.txt", "w") as f:
        f.write("Target file content")

if not os.path.exists("link.txt"):
    os.symlink("target.txt", "link.txt")

# Regular stat follows symlinks
target_stats = os.stat("link.txt")
print(f"Target file size: {target_stats.st_size} bytes")

# lstat gets info about the link itself
link_stats = os.lstat("link.txt")
print(f"\nLink info:")
print(f"Size: {link_stats.st_size} bytes")
print(f"Is symlink: {stat.S_ISLNK(link_stats.st_mode)}")

# Compare the two
print("\nComparison:")
print(f"Same inode: {target_stats.st_ino == link_stats.st_ino}")
print(f"Same device: {target_stats.st_dev == link_stats.st_dev}")

此示例演示了在使用符号链接时 os.stat 和 os.lstat 之间的区别。 报告的链接大小是它包含的路径的长度。

请注意,当您需要在应用程序中专门检测和处理符号链接时,os.lstat 特别有用。

平台特定属性

某些 stat 属性是平台特定的。 此示例显示了如何在不可用时安全地访问它们,并使用回退行为。

platform_stats.py
import os
import platform
import sys

file_path = sys.executable  # Using Python executable as example
stats = os.stat(file_path)

print(f"System: {platform.system()}")
print(f"File: {file_path}")

# Common attributes
print(f"\nCommon attributes:")
print(f"Size: {stats.st_size} bytes")
print(f"Mode: {oct(stats.st_mode)}")

# Platform-specific attributes
print("\nPlatform-specific attributes:")
if hasattr(stats, 'st_file_attributes'):  # Windows
    print(f"File attributes: {stats.st_file_attributes}")
    
if hasattr(stats, 'st_birthtime'):  # macOS and some Unix
    print(f"Birth time: {stats.st_birthtime}")
elif hasattr(stats, 'st_ctime'):  # Fallback
    print(f"Creation time: {stats.st_ctime}")

if hasattr(stats, 'st_blksize'):  # Unix block size
    print(f"Block size: {stats.st_blksize}")
    print(f"Blocks: {stats.st_blocks}")

此代码演示了如何使用 hasattr 安全地检查平台特定的属性。 它显示了各种系统上可用的不同属性。

该示例还强调了在使用文件系统元数据时编写跨平台代码的重要性。

安全注意事项

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。迄今为止,我撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程