权限错误:[Errno 13] 权限被拒绝

107

我遇到了这个错误:

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1538, in __call__
return self.func(*args)
File "C:/Users/Marc/Documents/Programmation/Python/Llamachat/Llamachat/Llamachat.py", line 32, in download
with open(place_to_save, 'wb') as file:
PermissionError: [Errno 13] Permission denied: '/goodbye.txt'

运行此命令时:

def download():
    # get selected line index
    index = films_list.curselection()[0]
    # get the line's text
    selected_text = films_list.get(index)
    directory = filedialog.askdirectory(parent=root, 
                                        title="Choose where to save your movie")
    place_to_save = directory + '/' + selected_text
    print(directory, selected_text, place_to_save)
    with open(place_to_save, 'wb') as file:
        connect.retrbinary('RETR ' + selected_text, file.write)
    tk.messagebox.showwarning('File downloaded', 
                              'Your movie has been successfully downloaded!' 
                              '\nAnd saved where you asked us to save it!!')

有人能告诉我我做错了什么吗?

规格: Python 3.4.4 x86 Windows 10 x64


4
place_to_save 应该只是 goodbye.txt 吗?我不确定 Windows 会如何表现,但在 Linux 上,您将写入根目录(/),这总是一个坏主意。您应该使用 os.path.join(directory, selected_text) 而不是手动字符串操作。 - Łukasz Rogalski
尝试使用open(place_to_save, 'w+')代替open(place_to_save, 'wb')。我记得看到一些其他的SO帖子也涉及到了同样的问题。 - DevLounge
4
一个 MCVE(最小化完整可复现示例)应该只有一行:open('/goodbye.txt', 'wb')。如果这也会引发错误,那么 tkinter 标签是无关紧要的,应该将其移除。该问题应该标记操作系统标签,因为这与问题相关。 - Terry Jan Reedy
2
print(directory, selected_text, place_to_save) 的输出是什么?我猜 directory 由于某些原因是一个空字符串。我建议在 filedialog.askdirectory 调用中添加 initialdir=r'c:/' - J.J. Hakala
1
@Mixone 我认为这是因为代码不够简洁。唯一相关的一行是 with open(place_to_save, 'wb') as file:,也许还有路径本身。此外,堆栈跟踪不完整。 - Gulzar
显示剩余6条评论
19个回答

181

如果您试图打开一个文件,但您的路径是一个文件夹,就会出现这种情况。

这很容易发生错误。

为了防止这种情况发生,请使用:

import os

path = r"my/path/to/file.txt"
assert os.path.isfile(path)
with open(path, "r") as f:
    pass

如果路径实际上是一个文件夹,断言将会失败。


7
我希望原问题提出者能接受这个答案。关于这个错误有很多很多的问题,而这是唯一一个真正正确的答案。经常出现这个错误,即使文件权限设置正确,所以答案必须是其他的原因。这就是它。 - Nesha25

45

有三种主要方法可以在Windows上获得管理员执行权限。

  1. cmd.exe以管理员身份运行
  2. 创建以提升的权限执行文件的快捷方式
  3. 更改python可执行文件的权限(不推荐)

A) 以管理员身份运行cmd.exe

由于Windows中没有sudo命令,您必须以管理员身份运行终端(cmd.exe)才能达到等同于sudo的权限级别。您可以通过两种方式实现:

  1. 手动

    • C:\Windows\system32 中找到 cmd.exe
    • 右键单击它
    • 选择 以管理员身份运行
    • 然后将打开命令提示符窗口在目录 C:\Windows\system32
    • 进入您的项目目录
    • 运行你的程序
  2. 通过快捷键

    • 按下 Windows 键(通常位于 altctrl 之间)+ X
    • 会出现一个包含各种管理员任务的小弹出列表。
    • 选择 命令提示符 (管理员)
    • 进入您的项目目录
    • 运行你的程序

通过这样做,您正在以管理员身份运行,因此该问题不应再存在。

B) 创建带有提升权限的快捷方式

  1. python.exe创建一个快捷方式
  2. 右键单击快捷方式,选择属性
  3. 更改快捷方式目标为类似于"C:\path_to\python.exe" C:\path_to\your_script.py"的内容
  • 在快捷方式的属性面板中单击“高级”,并单击“以管理员身份运行”选项
  • 答案由这个问题中的delphifirst贡献

    C)更改python可执行文件的权限(不建议)

    这是一种可能性,但我强烈不建议您这样做。

    只需找到python可执行文件并将其设置为每次以管理员身份运行即可。这可能会导致文件创建方面的问题(它们仅限于管理员),或者可能需要非管理员身份运行的模块出现问题。


    1
    如果这种情况发生在PyCharm中怎么办?我无法将管理员权限授予python.exe,因为这是一台工作电脑。 - Gulzar
    在这种情况下,您可能需要联系您的IT支持团队。或者将文件创建/删除移动到您的工作电脑上具有写入访问权限的目录中。 - Mixone
    1
    如果可以的话,也请尝试以管理员身份运行PyCharm,而不是python.exe。 - Mixone
    1
    @Mixone 为什么OP需要管理员权限?如果他拥有目标文件夹和程序,那么级别肯定匹配吧?如何调试运行级别以及特定目标所需的级别? - Neil_UK
    @Neil_UK 我相信这是因为他们的代码允许用户选择保存目录,而一些工作和学校的电脑有很多GPO策略阻止对某些共享文件夹的写入访问,如果他没有所有权,他需要权限,你知道由于你的用户级别在微软中的情况。 - Mixone

    43

    确保您要写入的文件已关闭。


    11

    更改要保存到的目录的权限,以使所有用户具有读写权限。


    4

    我遇到的问题是文件被隐藏了(文件具有隐藏属性):
    在python中如何解决这个问题:

    编辑:强调不安全的方法,谢谢d33tah

    # Use the method nr 1, nr 2 is vulnerable
    
    # 1
    # and just to let you know there is also this way
    # so you don't need to import os
    import subprocess
    subprocess.check_call(["attrib", "-H", _path])
    
    
    # Below one is unsafe meaning that if you don't control the filePath variable
    # there is a possibility to make it so that a malicious code would be executed
    
    import os
    
    # This is how to hide the file
    os.system(f"attrib +h {filePath}")
    file_ = open(filePath, "wb")
    >>> PermissionError <<<
    
    
    # and this is how to show it again making the file writable again:
    os.system(f"attrib -h {filePath}")
    file_ = open(filePath, "wb")
    # This works
    
    

    3
    警告:这里的前两个代码片段存在一个名为OS命令注入的漏洞:https://www.whitehatsec.com/glossary/content/os-command-injection;始终使用subprocess,永远不要将shell=True或os.system与用户控制的变量组合在一起。 - d33tah

    3
    问题可能出在你想要打开的文件路径上。试着打印出路径,看看是否正确。 我之前也遇到过类似的问题。
    def scrap(soup,filenm):
    htm=(soup.prettify().replace("https://","")).replace("http://","")
    if ".php" in filenm or ".aspx" in filenm or ".jsp" in filenm:
        filenm=filenm.split("?")[0]
        filenm=("{}.html").format(filenm)
        print("Converted a  file into html that was not compatible")
    
    if ".aspx" in htm:
        htm=htm.replace(".aspx",".aspx.html")
        print("[process]...conversion fron aspx")
    if ".jsp" in htm:
        htm=htm.replace(".jsp",".jsp.html")
        print("[process]..conversion from jsp")
    if ".php" in htm:
        htm=htm.replace(".php",".php.html")
        print("[process]..conversion from php")
    
    output=open("data/"+filenm,"w",encoding="utf-8")
    output.write(htm)
    output.close()
    print("{} bits of data written".format(len(htm)))
    

    但是在添加了这段代码之后:
    nofilenametxt=filenm.split('/')
    nofilenametxt=nofilenametxt[len(nofilenametxt)-1]
    if (len(nofilenametxt)==0):
        filenm=("{}index.html").format(filenm)
    

    3
    您可以以管理员身份运行CMD,并使用cacls.exe更改目录的权限。例如:
    cacls.exe c: /t /e /g everyone:F # means everyone can totally control the C: disc
    

    3

    我遇到了类似的问题。一开始我以为是系统出了问题,但是使用shutil模块中的shutil.copytree()函数解决了我的问题!


    2

    当我运行一个程序写入已打开的文件时,遇到了这个错误。在关闭文件并重新运行程序后,程序无错误地运行并按预期工作。


    1
    请添加更多细节以扩展您的答案,例如工作代码或文档引用。 - Community

    2
    在我的情况下,我只需将.idlerc目录隐藏起来。所以,我所要做的就是将该目录设置为隐藏,并使recent-files.lst文件不再隐藏,之后问题就得到了解决。

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