题 如何检查文件是否存在?


如何在不使用文件的情况下查看文件是否存在 try 声明?


4361
2017-09-17 12:55


起源




答案:


如果您检查的原因是这样,您可以做类似的事情 if file_exists: open_it(),使用它更安全 try 试图打开它。检查然后打开风险,删除或移动文件或检查时以及尝试打开文件时。

如果您不打算立即打开文件,则可以使用 os.path.isfile

返回 True 如果path是现有的常规文件。这遵循符号链接,所以两者 islink() 和 ISFILE() 对于同一条路径可以是真的。

import os.path
os.path.isfile(fname) 

如果你需要确定它是一个文件。

从Python 3.4开始, pathlib 模 提供面向对象的方法(向后移植到 pathlib2 在Python 2.7)中:

from pathlib import Path

my_file = Path("/path/to/file")
if my_file.is_file():
    # file exists

要检查目录,请执行以下操作:

if my_file.is_dir():
    # directory exists

检查一下 Path 对象存在独立于是文件还是目录,使用 exists()

if my_file.exists():
    # path exists

你也可以使用 resolve() 在一个 try 块:

try:
    my_abs_path = my_file.resolve()
except FileNotFoundError:
    # doesn't exist
else:
    # exists

3963
2017-09-17 12:57



关于第一个注释(如果在打开之前检查,请使用“try”),不幸的是,如果你想打开以确保它存在,因为'a'模式将创建(如果不存在),这将不起作用。 - makapuf
我明白了 os.path.isfile 不存在。 - JeromeJ


你有 os.path.exists 功能:

import os.path
os.path.exists(file_path)

这回来了 True 对于文件和目录,但您可以改为使用

os.path.isfile(file_name)

测试它是否是一个特定的文件。它遵循符号链接。


1626
2017-09-17 12:57





不像 isfile()exists() 将返回 True 对于目录。
因此,根据您是否只需要普通文件或目录,您将使用 isfile() 要么 exists()。这是一个简单的REPL输出。

>>> print os.path.isfile("/etc/password.txt")
True
>>> print os.path.isfile("/etc")
False
>>> print os.path.isfile("/does/not/exist")
False
>>> print os.path.exists("/etc/password.txt")
True
>>> print os.path.exists("/etc")
True
>>> print os.path.exists("/does/not/exist")
False

837
2017-09-17 15:01





import os.path

if os.path.isfile(filepath):

468
2017-09-17 12:55





使用 os.path.isfile() 同 os.access()

import os
import os.path

PATH='./file.txt'

if os.path.isfile(PATH) and os.access(PATH, os.R_OK):
    print "File exists and is readable"
else:
    print "Either the file is missing or not readable"

223
2018-01-16 05:57



有多种条件,其中一些是多余的,是 减 清楚明确。 - wim
这也是多余的。如果文件不存在, os.access() 将返回false。 - user207421
@EJP在linux文件中可以存在但不可访问。 - e-info128


import os
os.path.exists(path) # Returns whether the path (directory or file) exists or not
os.path.isfile(path) # Returns whether the file exists or not

209
2017-09-17 12:56



这个答案是对的。 os.path.exists 对于非文件的内容(如目录)返回true。这给出了误报。查看推荐的其他答案 os.path.isfile。 - Chris Johnson
目录是一种文件 unix.stackexchange.com/questions/197439/... - James Roth


这是检查文件是否存在的最简单方法。只是 因为 检查时存在的文件没有 保证 当你需要打开它时它会在那里。

import os
fname = "foo.txt"
if os.path.isfile(fname):
    print("file does exist at this time")
else:
    print("no such file exists at this time")

139
2018-06-27 13:38



只要你打算访问该文件,竞争条件 确实存在,无论你的程序是如何构建的。您的程序无法保证计算机上的其他进程未修改该文件。这就是Eric Lippert所说的 外生的例外。您无法通过事先检查文件的存在来避免它。 - Isaac Supeene
@IsaacSupeene最佳做法是使(文件)操作窗口尽可能小,然后进行适当的异常处理 - un33k


2017/12/22

尽管几乎所有可能的方式都列在(至少一个)现有答案中(例如 Python 3.4 添加了特定的东西),我会尝试将所有内容组合在一起。

注意:每一块 蟒蛇 我要发布的标准库代码属于版本 3.5.3 (doc引用是版本 3 具体)。

问题陈述

  1. 检查文件(值得商榷:还有文件夹(“特殊”文件)?)存在
  2. 不要用 try / except / else / finally 块

可能的解决方案

  1. [Python]:os.path。存在路径 (还要检查其他功能家庭成员 os.path.isfileos.path.isdiros.path.lexists 对于略有不同的行为)

    os.path.exists(path)
    

    返回 True 如果 路径 指现有路径或打开文件描述符。返回 False 对于破碎的符号链接。在某些平台上,此功能可能会返回 False 如果未授予执行权限 os.stat() 在请求的文件上,即使是 路径 身体存在。

    一切都很好,但是如果跟随导入树:

    • os.path  - posixpath.py (ntpath.py

      • genericpath.py,行 〜#20 +

        def exists(path):
            """Test whether a path exists.  Returns False for broken symbolic links"""
            try:
                st = os.stat(path)
            except os.error:
                return False
            return True
        

    它只是一个 try/except 挡住了 [Python]:os。统计path,*,dir_fd = None,follow_symlinks = True。所以,你的代码是 try/except 免费,但在框架中较低(至少)  这样的块。这也适用于其他功能(包含  os.path.isfile)。

    1.1。 [Python]:pathlib.Path。is_file()

    • 这是一个发烧友(还有更多 蟒蛇ic)处理路径的方式,
    • 在引擎盖下,确实如此 究竟 一样的东西 (pathlib.py,行 〜#1330):

      def is_file(self):
          """
          Whether this path is a regular file (also True for symlinks pointing
          to regular files).
          """
          try:
              return S_ISREG(self.stat().st_mode)
          except OSError as e:
              if e.errno not in (ENOENT, ENOTDIR):
                  raise
              # Path doesn't exist or is a broken symlink
              # (see https://bitbucket.org/pitrou/pathlib/issue/12/)
              return False
      
  2. [Python]:使用语句上下文管理器。或者:

    • 创建一个:

      class Swallow:  # Dummy example
          swallowed_exceptions = (FileNotFoundError,)
      
          def __enter__(self):
              print("Entering...")
      
          def __exit__(self, exc_type, exc_value, exc_traceback):
              print("Exiting:", exc_type, exc_value, exc_traceback)
              return exc_type in Swallow.swallowed_exceptions  # only swallow FileNotFoundError (not e.g. TypeError - if the user passes a wrong argument like None or float or ...)
      
      • 它的用法 - 我会复制它 isfile 行为(请注意,这仅用于演示目的,请执行此操作  试图写这样的代码 生产):

        import os
        import stat
        
        
        def isfile_seaman(path):  # Dummy func
            result = False
            with Swallow():
                result = stat.S_ISREG(os.stat(path).st_mode)
            return result
        
    • 使用 [Python]:contextlib。压制*例外  - 是的 特别 旨在有选择地抑制异常


    但是,它们似乎是包装纸 try/except/else/finally 块,如 [Python]:The  声明 状态:

    这允许共同 尝试......最后 要封装的使用模式以便于重用。

  3. 文件系统遍历函数(并搜索匹配项的结果)


    由于这些迭代文件夹,(在大多数情况下)它们对我们的问题是低效的(有例外,如非通配符 glob的bing - 正如@ShadowRanger指出的那样,所以我不会坚持他们。更不用说在某些情况下,可能需要文件名处理。

  4. [Python]:os。访问path,mode,*,dir_fd = None,effective_ids = False,follow_symlinks = True 他的行为很接近 os.path.exists (实际上它更宽,主要是因为2ND 论据)

    • 用户权限 可能会限制文件“可见性”,因为doc说明:

      ...测试调用用户是否具有指定的访问权限 路径模式 应该 F_OK 测试路径的存在...

    os.access("/tmp", os.F_OK)
    

    因为我也在工作 C,我也使用这种方法,因为在引擎盖下,它调用 本地人 API小号 (再次,通过 “$ {} PYTHON_SRC_DIR /Modules/posixmodule.c”),但它也打开了一扇门 用户错误,而不是 蟒蛇ic作为其他变种。所以,正如@AaronHall正确指出的那样,除非你知道你在做什么,否则不要使用它:

    注意:调用原生 APIs也可以通过 [蟒蛇]: ctypes的  - Python的外部函数库,但在大多数情况下,它更复杂。

    赢得 具体):自从 msvcr *vcruntime *)出口一个 [MSDN]:_ access,_waccess 函数族也是,这是一个例子:

    Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import os, ctypes
    >>> ctypes.CDLL("msvcrt")._waccess(u"C:\\Windows\\System32\\cmd.exe", os.F_OK)
    0
    >>> ctypes.CDLL("msvcrt")._waccess(u"C:\\Windows\\System32\\___cmd.exe", os.F_OK)
    -1
    

    笔记

    • 虽然这不是一个好习惯,但我正在使用 os.F_OK 在通话中,但这只是为了清晰(它的价值是 0
    • 我在用着 _waccess 以便相同的代码可以工作 Python3 和 Python2 (尽管 统一 它们之间的相关差异)
    • 虽然这针对一个非常特定的领域, 在之前的任何答案中都没有提到它


    LNX (Ubtu(16 x64))同行:

    Python 3.5.2 (default, Nov 17 2016, 17:05:23)
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import os, ctypes
    >>> ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6").access(b"/tmp", os.F_OK)
    0
    >>> ctypes.CDLL("/lib/x86_64-linux-gnu/libc.so.6").access(b"/tmp1", os.F_OK)
    -1
    

    笔记

    • 而是硬编码 的libc的路径(“/lib/x86_64-linux-gnu/libc.so.6”)可能(并且很可能会)在各系统之间变化, None (或空字符串)可以传递给 CDLL 构造函数(ctypes.CDLL(None).access(b"/tmp", os.F_OK))。根据 [男人]:DLOPEN(3)

      如果 文件名 为NULL,则返回的句柄为main   程序。当给予 对dlsym(),此句柄导致搜索a   主程序中的符号,后跟加载的所有共享对象   程序启动,然后加载所有共享对象 的dlopen()   国旗 RTLD_GLOBAL

      • 主要(当前)计划(蟒蛇)与之相关联 的libc,所以它的符号(包括 access)将被加载
      • 因为功能如此,所以必须小心处理 mainPy_Main 和(所有)其他人可用;打电话给他们可能会产生灾难性后果(在当前的节目中)
      • 这也不适用于 赢得 (但这不是什么大问题,因为 MSVCRT.DLL位于 的 “%SystemRoot%\ SYSTEM32” 在... %路径% 默认)。我想进一步采取行动并复制这种行为 赢得 (并提交补丁),但事实证明, [MSDN]:GetProcAddress函数 只是“看到” 出口 符号,所以除非有人将主要可执行文件中的函数声明为 __declspec(dllexport) (为什么在地球上 定期 人会这样做吗?),主程序是可加载的,但几乎无法使用
  5. 安装一些3RD 具有文件系统功能的派对模块

    最有可能的是,将依赖于上述方法之一(可能需要轻微的自定义)。
    一个例子是(再次, 赢得 具体) [GitHub]:用于Windows的Python(pywin32)扩展,这是一个 蟒蛇 包装 WINAPI秒。

    但是,由于这更像是一种解决方法,我在这里停下来。

  6. 另一个(跛脚)解决方法(gainarie)(就像我喜欢称之为) 系统管理员 方法:使用 蟒蛇 作为执行shell命令的包装器

    • 赢得

      (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe\" > nul 2>&1'))"
      0
      
      (py35x64_test) e:\Work\Dev\StackOverflow\q000082831>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" -c "import os; print(os.system('dir /b \"C:\\Windows\\System32\\cmd.exe.notexist\" > nul 2>&1'))"
      1
      
    • LNX (Ubtu):

      [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp\" > /dev/null 2>&1'))"
      0
      [cfati@cfati-ubtu16x64-0:~]> python3 -c "import os; print(os.system('ls \"/tmp.notexist\" > /dev/null 2>&1'))"
      512
      

底线

  •  使用 try / except / else / finally 块,因为它们可以防止你遇到一系列令人讨厌的问题。我能想到的一个反例是性能:这样的块是昂贵的,所以尽量不要将它们放在它应该每秒运行数十万次的代码中(但是因为(在大多数情况下)它涉及磁盘访问,事实并非如此)。

最后的注释

  • 我将尽力保持最新,欢迎提出任何建议,我会将有用的任何内容纳入到答案中

137
2018-06-20 19:28



你能详细说明这个陈述吗? “虽然这不是一个好习惯,我在通话中使用os.F_OK,但这只是为了清晰(它的值为0)” - sk8asd123
@ sk8asd123:在注释中很难做到这一点:通常,最好使用常量与它们一起使用的函数。这适用于使用定义相同常量的多个模块,因为有些模块可能不是最新的,并且最好使函数和常量保持同步。在工作时 ctypes的 (直接调用函数)我应该定义常量(来自 MSDN),或者根本不使用常数。这只是我使用的指南,在99.9%它可能没有区别(功能上)。 - CristiFati
@CristiFati:截至3.6, glob.iglob (和 glob.glob 以及)是基于 os.scandir,现在很懒;要获得10M文件目录中的第一个匹配,您只需扫描,直到达到第一个匹配。如果你使用,甚至在3.6之前 glob 没有任何通配符的方法,功能很聪明:它知道你只能有一个命中,所以 它将globbing简化为just os.path.isdir 要么 os.path.lexists (取决于路径是否以 /)。 - ShadowRanger
我的评论的第二部分(非通配的globbing实际上并没有迭代文件夹,从来没有)确实意味着它是一个非常有效的解决问题的方法(比直接调用慢) os.path.isdir 要么 os.path.lexist 因为它是一堆Python级函数调用和字符串操作,然后才决定有效路径是否可行,但没有额外的系统调用或I / O工作,这要慢几个数量级)。 - ShadowRanger