ZetCode

Python os.fchmod 函数

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

本综合指南探讨了 Python 的 os.fchmod 函数,该函数使用文件描述符更改文件权限。我们将介绍权限位、八进制表示法以及实用的文件权限修改示例。

基本定义

os.fchmod 函数根据文件描述符而不是路径来更改文件的模式(权限)。它类似于 os.chmod,但适用于已打开的文件。

主要参数:fd(文件描述符),mode(八进制权限位)。 需要文件已经打开。 仅在类 Unix 系统上可用。

使用 fchmod 更改文件权限

这个基本示例演示了如何使用文件描述符更改文件权限。 我们首先打开一个文件,然后修改其权限。

basic_fchmod.py
import os

# Create or open a file
file_path = "testfile.txt"
with open(file_path, "w") as f:
    f.write("Sample content")
    
    # Get file descriptor
    fd = f.fileno()
    
    # Change permissions to read-only for owner
    os.fchmod(fd, 0o400)
    print(f"Changed permissions of {file_path} to 0400 (read owner)")

该示例创建一个文件,获取其文件描述符,并将权限设置为 0400(所有者只读)。 0o 前缀表示八进制表示法。

请注意,与使用路径的 chmod 不同,在使用 fchmod 更改权限时,文件必须保持打开状态。

设置不同的权限组合

此示例展示了使用 fchmod 的各种常见权限组合。 我们演示了针对不同用户的读取、写入和执行权限。

permission_combinations.py
import os

file_path = "data.txt"
with open(file_path, "w") as f:
    fd = f.fileno()
    
    # Read and write for owner, read for others
    os.fchmod(fd, 0o644)
    print("Set permissions to 0644 (rw-r--r--)")
    
    # Read, write, execute for owner, read and execute for group/others
    os.fchmod(fd, 0o755)
    print("Set permissions to 0755 (rwxr-xr-x)")
    
    # Read and write for owner only
    os.fchmod(fd, 0o600)
    print("Set permissions to 0600 (rw-------)")
    
    # Read, write, execute for owner, nothing for others
    os.fchmod(fd, 0o700)
    print("Set permissions to 0700 (rwx------)")

每个 fchmod 调用都会立即更改文件的权限。 八进制值代表所有者、组和其他用户的标准 Unix 权限位。

第一个数字表示特殊位(setuid、setgid、sticky),而接下来的三个数字表示所有者、组和其他用户的权限。

处理特殊权限位

除了标准权限之外,fchmod 还可以设置特殊位,例如 setuid、setgid 和 sticky。 此示例演示了它们的用法。

special_bits.py
import os
import stat

script_path = "special_script.sh"
with open(script_path, "w") as f:
    f.write("#!/bin/sh\necho 'Hello World'")
    fd = f.fileno()
    
    # Set setuid bit (04000)
    os.fchmod(fd, 0o4755)
    print("Set setuid bit (04755)")
    
    # Set setgid bit (02000)
    os.fchmod(fd, 0o2755)
    print("Set setgid bit (02755)")
    
    # Set sticky bit (01000)
    os.fchmod(fd, 0o1755)
    print("Set sticky bit (01755)")
    
    # Combine setuid and setgid
    os.fchmod(fd, 0o6755)
    print("Set both setuid and setgid bits (06755)")

特殊位使用第一个八进制数字设置:4 表示 setuid,2 表示 setgid,1 表示 sticky。 这些位具有安全隐患,应谨慎使用。

请注意,有效用户必须具有适当的权限才能设置这些特殊权限位。

使用 stat 常量设置权限

我们可以使用 stat 模块中的常量,而不是原始的八进制数字,使权限设置更具可读性和可维护性。

stat_constants.py
import os
import stat

file_path = "config.cfg"
with open(file_path, "w") as f:
    fd = f.fileno()
    
    # Read/write owner, read group/others using stat constants
    mode = (stat.S_IRUSR | stat.S_IWUSR | 
            stat.S_IRGRP | stat.S_IROTH)
    os.fchmod(fd, mode)
    print("Set permissions using stat constants (rw-r--r--)")
    
    # Read/write/execute owner, read/execute group/others
    mode = (stat.S_IRWXU | 
            stat.S_IRGRP | stat.S_IXGRP |
            stat.S_IROTH | stat.S_IXOTH)
    os.fchmod(fd, mode)
    print("Set permissions using stat constants (rwxr-xr-x)")

stat 模块为权限位提供人类可读的常量,可以使用按位 OR 运算进行组合。 这使代码更具自文档性。

每个常量代表一个特定的权限位(例如,S_IRUSR = 所有者读取,S_IWGRP = 组写入)。

使用 fchmod 进行错误处理

此示例演示了使用 fchmod 时的正确错误处理,包括权限被拒绝的情况和无效的文件描述符。

error_handling.py
import os
import errno

file_path = "protected_file.txt"
try:
    # Try to open a protected file
    with open(file_path, "w") as f:
        fd = f.fileno()
        try:
            os.fchmod(fd, 0o777)
            print("Successfully changed permissions")
        except PermissionError as e:
            print(f"Permission denied: {e}")
        except OSError as e:
            if e.errno == errno.EBADF:
                print("Invalid file descriptor")
            else:
                print(f"OS error: {e}")
except IOError as e:
    print(f"Cannot open file: {e}")

该示例展示了如何处理使用 fchmod 时可能发生的各种错误情况。 缺少权限时会发生 PermissionError,而 EBADF 表示无效的文件描述符。

修改文件权限时,正确的错误处理至关重要,因为这些操作通常需要提升的权限。

比较 fchmod 和 chmod

此示例重点介绍了 fchmod(文件描述符)和 chmod(路径)更改文件权限的方法之间的差异。

fchmod_vs_chmod.py
import os
import time

file_path = "compare.txt"

# Using chmod (path-based)
with open(file_path, "w") as f:
    f.write("Content")
os.chmod(file_path, 0o644)
print("Used chmod to set permissions via path")

# Using fchmod (descriptor-based)
with open(file_path, "r+") as f:
    fd = f.fileno()
    os.fchmod(fd, 0o600)
    print("Used fchmod to set permissions via descriptor")
    
    # Demonstrate advantage: file renamed while open
    new_path = "renamed.txt"
    os.rename(file_path, new_path)
    os.fchmod(fd, 0o400)
    print("Changed permissions after rename with fchmod")

主要区别在于 fchmod 在打开的文件描述符上工作,使其不受可能影响 chmod 操作的路径更改(例如重命名)的影响。

当您需要确保修改的是已打开的同一文件,而不管文件系统更改如何时,fchmod 特别有用。

安全注意事项

最佳实践

资料来源

作者

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

列出所有 Python 教程