在Python中以特定权限写文件

56 投票
6 回答
75898 浏览
提问于 2025-04-16 15:30

我想创建一个文件,这个文件只有用户自己可以读和写,权限设置为0600

我是不是只能通过像下面这样使用os.open()来实现呢?

import os
fd = os.open('/path/to/file', os.O_WRONLY, 0o600)
myFileObject = os.fdopen(fd)
myFileObject.write(...)
myFileObject.close()

理想情况下,我希望能使用with这个关键词,这样可以自动关闭文件对象。有没有更好的方法来实现我上面说的呢?

6 个回答

12

更新
大家好,感谢你们给我的点赞,但我得反对我之前提出的解决方案。原因是用这种方式处理时,会有一段时间(虽然很短),文件是存在的,但权限设置不正确,这样就会留下安全隐患,甚至可能导致程序出错。
当然,最好的办法是一开始就创建文件时就设置好正确的权限——在这方面,使用Python的with只是个锦上添花的做法。

所以,请把这个回答当作“不要这样做”的例子。

原始帖子

你可以使用os.chmod来代替:

>>> import os
>>> name = "eek.txt"
>>> with open(name, "wt") as myfile:
...   os.chmod(name, 0o600)
...   myfile.write("eeek")
...
>>> os.system("ls -lh " + name)
-rw------- 1 gwidion gwidion 4 2011-04-11 13:47 eek.txt
0
>>>

(注意,在Python中使用八进制数时需要明确表示,前面加上"0o",比如"0o600"。在Python 2.x中可以直接写0600,但那样既容易误解又已经不推荐使用了。)

不过,如果你的安全性非常重要,最好还是使用os.open来创建文件,然后用os.fdopenos.open返回的文件描述符中获取一个Python文件对象。

34

这个回答主要解决了关于 vartec 的回答 中的几个问题,特别是关于 umask 的问题。

import os
import stat

# Define file params
fname = '/tmp/myfile'
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL  # Refer to "man 2 open".
mode = stat.S_IRUSR | stat.S_IWUSR  # This is 0o600.
umask = 0o777 ^ mode  # Prevents always downgrading umask to 0.

# For security, remove file with potentially elevated mode
try:
    os.remove(fname)
except OSError:
    pass

# Open file descriptor
umask_original = os.umask(umask)
try:
    fdesc = os.open(fname, flags, mode)
finally:
    os.umask(umask_original)

# Open file handle and write to file
with os.fdopen(fdesc, 'w') as fout:
    fout.write('something\n')

如果你想要的权限模式是 0600,可以更清楚地写成八进制数 0o600。更简单的方法是直接使用 stat 模块。

虽然旧文件会先被删除,但还是有可能出现竞争条件。也就是说,如果在创建文件时加上 os.O_EXCLos.O_CREAT,那么如果文件已经存在,就不会再创建这个文件。这是一个必要的安全措施,可以防止打开一个可能已经存在且权限可能更高的文件。在 Python 3 中,如果文件已经存在,会抛出 FileExistsError 和 [Errno 17] 的错误。

如果没有先把 umask 设置为 0 或者 0o777 ^ mode,可能会导致 os.open 设置了错误的权限模式。这是因为默认的 umask 通常不是 0,它会影响你指定的权限模式。举个例子,如果我原来的 umask2(也就是 0o002),而我指定的模式是 0o222,如果我没有先设置 umask,那么最终创建的文件的权限模式可能是 0o220,这就不是我想要的。根据 man 2 open 的说明,创建文件的模式是 mode & ~umask

而且,umask 会尽快恢复到它的原始值。这个获取和设置的过程在多线程应用中不是线程安全的,所以需要使用 threading.Lock

想了解更多关于 umask 的信息,可以参考 这个讨论

42

问题是什么呢?file.close() 这个命令会关闭文件,即使这个文件是用 os.open() 打开的。

with os.fdopen(os.open('/path/to/file', os.O_WRONLY | os.O_CREAT, 0o600), 'w') as handle:
  handle.write(...)

撰写回答