确定目录是否可写

ill*_*ger 93 python directory permissions operating-system file

Python中确定目录对于执行脚本的用户是否可写的最佳方法是什么?由于这可能涉及使用os模块,我应该提到我在*nix环境下运行它.

Max*_*keh 162

虽然Christophe建议的是更Pythonic解决方案,但os模块确实具有os.access函数来检查访问:

os.access('/path/to/folder', os.W_OK) #W_OK用于写入,R_OK用于阅读等.

  • 如果要将文件写入目录,则仅测试写入位的目录是不够的.如果要写入目录,还需要测试执行位.os.access('/ path/to/folder',os.W_OK | os.X_OK)使用os.W_OK本身你只能删除目录(并且只有当该目录为空时) (48认同)
  • 根据具体情况,即使在Python中,"更容易请求宽恕"也不是最好的方法.有时建议像所提到的os.access()方法一样"询问权限",例如当必须捕获错误的概率很高时. (4认同)
  • 也许程序只是想知道而无需实际编写。它可能只想根据该属性更改GUI的外观和/或行为。在那种情况下,我不会像测试那样将pythonic写入和删除文件。 (4认同)
  • 另一个问题是`os.access()`是使用*real*UID和GID进行检查,而不是使用*有效*进行检查.这可能会导致SUID/SGID环境中的怪异.('但脚本运行setuid root,为什么不能写入文件?') (3认同)
  • 刚刚在 Windows 网络共享上进行了测试。即使我没有写访问权限,`os.access(dirpath, os.W_OK | os.X_OK)` 也会返回 True。 (3认同)
  • 正如已经说过的,这在 Windows 上会给出错误的结果...请在您的答案中添加评论,然后我将删除反对票。 (3认同)

Chr*_*heD 67

建议这可能看起来很奇怪,但一个常见的Python习语是

要求宽恕比获得许可更容易

在这个成语之后,有人会说:

尝试写入相关目录,如果您没有权限,请捕获错误.

  • 不管是否是Python,这是测试访问权限的最可靠方法. (5认同)
  • 这还可以处理写入磁盘时可能发生的其他错误 - 例如,没有剩余磁盘空间.这是尝试的力量..你不需要记住可能出错的一切;-) (5认同)
  • 多谢你们.因为速度是我在这里做的一个重要因素决定与os.access一起使用,尽管我当然可以理解"请求宽恕比获得许可更容易"的优点.;) (4认同)
  • 这是一个伟大的IDIO ...... - 尤其是当与另一个成语"除了:传递"相结合时 - 这样你就可以保持乐观并高度评价自己./讽刺了.现在我为什么要这样做,例如尝试在我的文件系统中的每个目录中写一些东西,以产生一个可写位置列表? (4认同)
  • 也许程序只是想知道而无需实际编写。它可能只想根据该属性更改GUI的外观和/或行为。在那种情况下,我不会像测试那样将pythonic写入和删除文件。 (4认同)
  • @illuminatedtiger:这是完美的飞行,只需要注意文档中的注释(http://docs.python.org/library/os.html#os.access) (2认同)
  • @Tomasz Gandor:我不认为`except: pass` 是普遍接受的习语:-)(在任何语言中)。话虽如此,在您的文件系统上编译可写位置列表从您创建它的那一刻起就注定要过时。这有什么用例?即使在您尝试写入(在代码中)之前检查您是否*可以* 写入目录中的一行,也不能保证任何类型(因为它不是原子操作)。无论如何,“尝试”仍然是您需要做的。 (2认同)
  • 我同意。正确的方法取决于情况-如果仍然要写入该目录-随便去找并捕获错误(EAFP)。但是,如果您需要写入目录A,B和C-并且仅发现C失败了,那么您可能浪费了(计算)时间和金钱(认为-云计算)。否则,您需要能够在此类“事务”失败后进行清理。好吧,无论如何您可能需要最后一个。您仍可能会在TOCTOU中失去权限。 (2认同)

zak*_*zak 18

我使用该tempfile模块的解决方案:

import tempfile
import errno

def isWritable(path):
    try:
        testfile = tempfile.TemporaryFile(dir = path)
        testfile.close()
    except OSError as e:
        if e.errno == errno.EACCES:  # 13
            return False
        e.filename = path
        raise
    return True
Run Code Online (Sandbox Code Playgroud)

  • 这个方法不能使用`tempfile`.它只有在没有"OSError"意味着它有写入/删除权限时才有效.否则它将不会返回False,因为没有返回错误,脚本将不会继续执行或退出.没有任何回报.它只是停留在那条线上.但是,创建非临时文件(如khattam的答案)在允许或拒绝权限时都可以正常工作.救命? (3认同)

Roh*_*haq 10

偶然发现这个线程正在寻找某人的例子.对谷歌的第一个结果,恭喜!

人们在这个帖子中谈论Pythonic的做法,但没有简单的代码示例?在这里,对于其他任何偶然发现的人:

import sys

filepath = 'C:\\path\\to\\your\\file.txt'

try:
    filehandle = open( filepath, 'w' )
except IOError:
    sys.exit( 'Unable to write to file ' + filepath )

filehandle.write("I am writing this text to the file\n")
Run Code Online (Sandbox Code Playgroud)

这会尝试打开文件句柄进行写入,如果指定的文件无法写入,则会以错误退出:这更容易阅读,并且是一种更好的方法,而不是在文件路径或目录上进行预先检查,因为它避免了竞争条件; 在运行预检和实际尝试写入文件之间文件变为不可写的情况.

  • 这适用于文件,而不是 OP 要求的目录。您可以在目录中有一个文件,并且该目录不可写,但文件本身是可写的,如果该文件已经存在。这在系统管理中可能很重要,例如,您要创建希望已经存在但不希望人们使用日志目录作为临时空间的日志文件。 (2认同)

sve*_*erw 9

如果您只关心文件烫发,os.access(path, os.W_OK)应该按照您的要求进行操作.如果您想要知道是否可以写入目录,则需要open()一个用于写入的测试文件(它不应该预先存在),捕获并检查任何内容IOError,然后清理测试文件.

更一般地说,为了避免TOCTOU攻击(如果你的脚本以提升的权限运行,只有一个问题 - suid或cgi左右),你不应该真正相信这些提前测试,而是放弃私有,做open(),并期待这个IOError.


Joe*_*erg 7

检查模式位:

def isWritable(name):
  uid = os.geteuid()
  gid = os.getegid()
  s = os.stat(dirname)
  mode = s[stat.ST_MODE]
  return (
     ((s[stat.ST_UID] == uid) and (mode & stat.S_IWUSR)) or
     ((s[stat.ST_GID] == gid) and (mode & stat.S_IWGRP)) or
     (mode & stat.S_IWOTH)
     )
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案只适用于Unix. (4认同)

kha*_*tam 5

这是我根据 ChristopheD 的回答创建的内容:

import os

def isWritable(directory):
    try:
        tmp_prefix = "write_tester";
        count = 0
        filename = os.path.join(directory, tmp_prefix)
        while(os.path.exists(filename)):
            filename = "{}.{}".format(os.path.join(directory, tmp_prefix),count)
            count = count + 1
        f = open(filename,"w")
        f.close()
        os.remove(filename)
        return True
    except Exception as e:
        #print "{}".format(e)
        return False

directory = "c:\\"
if (isWritable(directory)):
    print "directory is writable"
else:
    print "directory is not writable"
Run Code Online (Sandbox Code Playgroud)