在 Python 中检查文件的权限

8

我正在尝试检查给定路径下文件的可读性。这是我的代码:

def read_permissions(filepath):
    '''Checks the read permissions of the specified file'''
    try:
        os.access(filepath, os.R_OK) # Find the permissions using os.access
    except IOError:
        return False

    return True

这段代码可以正常运行并返回True或False作为输出结果。然而,我想让errno的错误信息与其一起输出。我认为需要做如下修改(但我知道其中有问题):

def read_permissions(filepath):
    '''Checks the read permissions of the specified file'''
    try:
        os.access(filepath, os.R_OK) # Find the permissions using os.access
    except IOError as e:
        print(os.strerror(e)) # Print the error message from errno as a string

    print("File exists.")

然而,如果我输入一个不存在的文件,它会告诉我该文件存在。有人能帮我看看我做错了什么(以及我可以在将来避免这个问题的方法)吗?我没有看到任何人使用os.access尝试过这个。我也愿意尝试其他选项来测试文件的权限。有人能告诉我如何在出现错误时引发适当的错误消息吗?
此外,这可能也适用于我的其他函数(它们仍然使用os.access来检查其他内容,例如使用os.F_OK检查文件是否存在,以及使用os.W_OK检查文件的写入权限)。以下是我试图模拟的示例:
>>> read_permissions("located-in-restricted-directory.txt") # Because of a permission error (perhaps due to the directory)
[errno 13] Permission Denied
>>> read_permissions("does-not-exist.txt") # File does not exist
[errno 2] No such file or directory

我试图模拟的是通过返回适当的错误消息来解决问题。我希望这能帮助避免对我的问题产生任何困惑。

我应该指出,虽然我已经阅读了os.access文档,但我并不是在尝试稍后打开文件。我只是试图创建一个模块,其中一些组件要检查特定文件的权限。我有一个基准(我提到的第一段代码),它为我的其余代码作出决策。在这里,我只是试图以用户友好的方式再次编写它(不仅仅是TrueFalse,而是完整的消息)。由于IOError可以通过几种不同的方式引起(例如权限被拒绝或不存在的目录),因此我正在尝试让我的模块识别和发布问题。我希望这可以帮助您帮助我确定可能的解决方案。


except块后面的else块中尝试使用print("File exists.")。这是您正在寻找的行为吗? - Air
尝试使用return而不是print - Kevin Ji
我刚刚尝试了AirThomas的建议,但它给我相同的输出,说该文件存在,实际上并不存在。我将 print("File exists.") 放在 except 块之后的 else 块中。此外,mc10,我只是用 return 替换了 print,似乎也没有真正做任何事情。 - Zizouz212
1个回答

13

os.access在文件不存在时返回False,无论传递的模式参数是什么。

虽然在 os.access 的文档 中未明确说明此行为,但这并不令人惊讶;毕竟,如果文件不存在,您就无法访问它。像文档建议的那样检查access(2) man page会给出另一个线索,即access在各种条件下返回-1。无论如何,您可以像我一样在IDLE中检查返回值:

>>> import os
>>> os.access('does_not_exist.txt', os.R_OK)
False

在Python中,通常不鼓励在实际执行有用的操作之前检查类型等信息。这种哲学常常被用缩写EAFP表达,表示“宁愿请求原谅,也不要事先获得许可”。如果您再次参考文档,您将会发现这在当前情况下尤为相关:

注意: 在使用open() 执行打开文件之前使用access() 检查用户是否有授权等行为会创建一个安全漏洞,因为用户可能利用检查和打开文件之间的短时间间隔来操纵文件。最好使用EAFP技术。例如:

if os.access("myfile", os.R_OK):
    with open("myfile") as fp:
        return fp.read()
return "some default data"

最好这样写:

try:
    fp = open("myfile")
except IOError as e:
    if e.errno == errno.EACCES:
        return "some default data"
    # Not a permission error.
    raise
else:
    with fp:
        return fp.read()
如果你检查权限的原因不仅仅是在调用open()之前对用户进行二次确认,那么你可以参考如何使用Python检查文件是否存在?来获得一些建议。请记住,如果你真的需要引发异常,你可以随时自己raise它;没有必要去寻找野生异常。

由于IOError可能会以几种不同的方式出现(例如权限被拒绝或目录不存在),我正在尝试让我的模块识别并公布这个问题。

这就是上面第二种方法所做的事情。请见:

>>> try:
...     open('file_no_existy.gif')
... except IOError as e:
...     pass
...
>>> e.args
(2, 'No such file or directory')
>>> try:
...     open('unreadable.txt')
... except IOError as e:
...     pass
...
>>> e.args
(13, 'Permission denied')
>>> e.args == (e.errno, e.strerror)
True

但你需要选择一种方法。如果你要请求原谅,在一个try-except块中执行操作(打开文件),并适当处理后果。如果成功,那么你知道成功了,因为没有异常。

另一方面,如果你要征得许可(也称为LBYL,在跳跃之前查看)以这种方式和其他方式,你直到实际执行它才知道是否能成功打开文件。如果你检查权限后文件被移动了怎么办?如果有问题你没想到去检查怎么办?

如果你仍然想要征得许可,就不要使用try-except;因为你不是执行操作,所以不会抛出错误。而是使用带有对os.access调用的条件语句作为条件。


2
在您最后的示例中,使用 IOError 过于宽泛。相应地,您也可以捕获 FileNotFoundErrorPermissionError - Tomerikoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接