如何检查文件是否存在无例外?


5600

如何在不使用try语句的情况下检查文件是否存在?


2
这似乎是古典与EAFP讨论LBYL,例如见此相关的问题:stackoverflow.com/questions/1835756/using-try-vs-if-in-python
matth

如果您想知道它是否存在于磁盘上(直接或作为符号链接),是否可以读取或写入,也很重要。
托尔比约恩Ravn的安徒生

Answers:


5150

如果您要检查的原因是可以执行类似的操作if file_exists: open_it(),则使用try尝试来打开它会。检查然后打开可能会导致文件被删除或移动,或者介于检查和尝试打开之间的时间。

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

True如果path是现有的常规文件,则返回。这遵循符号链接,因此,对于同一路径,islink()isfile()都可以为true。

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

如果您需要确保它是一个文件。

从Python 3.4开始,该pathlib模块提供了一种面向对象的方法(pathlib2在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(strict=True)在一个try块中使用:

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

40
不幸的是,关于第一个备注(如果在打开前进行检查,请使用“ try”),如果您想打开以进行附加操作以确保它在之前存在,则将不起作用,因为如果不存在,则会创建“ a”模式。
makapuf

6
请注意,它FileNotFoundError是在Python 3中引入的。如果您还需要同时支持Python 2.7和Python 3,则可以使用IOErrorFileNotFoundError子类)stackoverflow.com/a/21368457/1960959
scottclowe

7
@makapuf您可以打开它进行“更新”(open('file', 'r+')),然后搜索到末尾。
kyrill

2
@kyrill的开放式寻求与终端开放(至少在posix系统上)不同。即使在打开文件的时间和写入的时间之间有其他事情修改了文件,“附加模式”也将始终正确地写入文件的末尾。如果有多种尝试同时写入同一文件,则打开进行写入/更新并最终查找可能会损坏文件数据。不幸的是,我相信在确保文件首先存在的情况下,唯一可以在竞争条件下打开的竞争方法是使用较低级别的os.open()例程代替(不带O_CREAT的O_APPEND)。
Foogod

1
@LorinczyZsigmond听起来像是依赖于实现的行为。想要共享资源?
kyrill

2110

您具有以下os.path.exists功能:

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

这会同时返回True文件和目录,但您可以改用

os.path.isfile(file_path)

测试它是否是专门的文件。它遵循符号链接。


965

不像isfile()exists()将返回True目录。因此,根据您只需要纯文件还是目录,您将使用isfile()exists()。这是一些简单的REPL输出:

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


319

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

import os

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")

60
具有多个条件,其中有一些是多余的,是不太清晰和明确。
2013年

10
这也是多余的。如果文件不存在,os.access()将返回false。
user207421 '18

9
@EJP在linux文件中可以存在但不可以访问。
e-info128

8
自从你以来import os,你不需要import os.path再做了,因为它已经是一部分osos.path如果只打算使用功能os.path而不是os本身使用功能,则只需要导入即可导入较小的内容,但是在使用os.accessand时os.R_OK,不需要第二次导入。
小丑19年

286
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

1
通常,将变量命名为与方法名称相同的做法不好。
Homunculus Reticulli

245

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

注意:我要发布的每个Python标准库代码都属于3.5.3版。

问题陈述

  1. 检查文件(可以争论:也是文件夹(“特殊”文件)吗?)是否存在
  2. 不要使用try / except / else / finally

可能的解决方案

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

    os.path.exists(path)

    返回True如果路径是指现有的路径或一个打开的文件描述符。返回False断开的符号链接。在某些平台上,即使未物理上存在路径,如果False未授予在请求的文件上执行os.stat()的权限,此函数也可能返回。

    一切都很好,但是如果遵循导入树:

    • os.path- posixpath.pyntpath.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

    它只是[Python 3]周围的try / 除了:操作系统。statpath,*,dir_fd = None,follow_symlinks = True。因此,您的代码是try / 除了免费的,但在帧堆栈中至少有一个这样的块。这也适用于其他功能(包括 os.path.isfile)。

    1.1。[Python 3]:路径。is_file()

    • 这是一种处理路径的更好的方式(以及更多的python 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 3]:使用语句上下文管理器。要么:

    • 创建一个:

      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 ...)
      • 而它的用法-我会复制os.path.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 3]:contextlib。抑制*例外 -这是具体地用于选择性地抑制异常设计


    但是,它们似乎是try / except / else / finally块的包装,如[Python 3]:with语句指出:

    这使得普通试试 ...... 除非 ...... 终于被封装为方便重复使用的使用模式。

  3. 文件系统遍历功能(并在结果中搜索匹配项)


    由于这些遍历文件夹,(在大多数情况下)它们对于我们的问题效率不高(有一些例外,例如非通配glob bing-如@ShadowRanger所指出的),所以我不再坚持使用它们。更不用说在某些情况下,可能需要处理文件名。

  4. [Python 3]:操作系统。访问路径,模式,*,dir_fd =无,effective_ids =假follow_symlinks =真的行为是接近os.path.exists(实际上这是2个,主要是因为更宽,第二参数)

    • 用户权限可能会限制文件“可见性”,如doc所述:

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

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

    自从我也工作Ç,我用这个方法,以及因为引擎盖下,它调用本地API小号(同样,通过“$ {} PYTHON_SRC_DIR /Modules/posixmodule.c”),但它也开辟了可能的栅极用户errors,它不像其他变体那样像Python ic。因此,正如@AaronHall正确指出的那样,除非您知道自己在做什么,否则不要使用它:

    注意:也可以通过[Python 3]调用本地API ctypes -Python的外部函数库,但是在大多数情况下,它更为复杂。

    特定于):由于vcruntime *msvcr *). dll导出[MS.Docs]:_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.notexist", os.F_OK)
    -1

    注意事项

    • 尽管这不是一个好习惯,但我os.F_OK在通话中使用了,但这只是为了清楚起见(其值为0
    • 我正在使用_waccess,以便相同的代码可在Python3Python2上使用(尽管它们之间存在与Unicode相关的区别)
    • 尽管这是针对非常特定的领域,但之前的任何答案都未提及


    LNXUbtu(16 64)以及)对应物:

    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"/tmp.notexist", os.F_OK)
    -1

    注意事项

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

      如果filename为NULL,则返回的句柄用于主程序。当给 dlsym()时,此句柄将在主程序中搜索符号,然后在程序启动时加载所有共享对象,然后在dlopen()中加载带有标志RTLD_GLOBAL的所有共享对象。

      • 主(当前)程序( python)与libc链接,因此其符号(包括访问)将加载)
      • 必须小心处理,因为像mainPy_Main这样的函数和(所有)其他功能都可用。打电话给他们可能会造成灾难性的影响(对当前程序)
      • 这也不适用于Win(但是这没什么大不了的,因为msvcrt.dll位于“%SystemRoot%\ System32”中,默认情况下位于%PATH%中)。我想进一步介绍并在Win上复制此行为(并提交补丁),但事实证明,[MS.Docs]:GetProcAddress函数仅“看到” 导出的符号,因此除非有人在主可执行文件中声明该函数如__declspec(dllexport)(为什么地球上普通的人会做的?),主程序加载,但几乎无法使用
  5. 安装一些具有文件系统功能的第三方模块

    最有可能的,将依赖于上述方法之一(可能需要进行一些自定义)。
    一个示例是(再次,特定于Win[GitHub]:mhammond / pywin32-Windows的Python(pywin32)扩展,它是WINAPIPython包装器。

    但是,由于这更像是一种解决方法,所以我在这里停止。

  6. 另一个(lam)解决方法(gainarie)是(我喜欢这样称呼)sysadmin方法:使用Python作为包装器执行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
    • 尼克斯LnxUbtu)):

      [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

底线

  • 不要使用 / 除外 / 其它 / 最后块,因为它们可以防止您遇到一系列令人讨厌的问题。我可以想到的一个反例是性能:此类块非常昂贵,因此请不要将它们放在应该每秒运行数十万次的代码中(但是(在大多数情况下,由于它涉及磁盘访问,事实并非如此)。

最后说明

  • 我将尝试使其保持最新状态,欢迎提出任何建议,我将结合所有有用的内容,使之成为答案

3
您能详细说明一下吗?“尽管这不是一个好习惯,但我在通话中使用了os.F_OK,但这只是为了清楚起见(其值为0)”
sk8asd123 '17

6
@ sk8asd123:很难在注释中添加它:通常,最好将常量与它们一起使用的函数一起使用。这适用于使用多个定义相同常量的模块,因为某些模块可能不是最新的,并且函数和常量最好是同步的。当使用ctypes(直接调用函数)时,我应该已经定义了常量(来自MSDN),或者根本不使用常量。这只是我使用的准则,在99.9%的范围内(功能上)可能没有什么区别。
CristiFati

3
@CristiFati:从3.6开始,glob.iglobglob.glob以及)都基于os.scandir,所以现在很懒。要获得10M文件目录中的第一个匹配,您只需扫描直到达到第一个匹配。甚至在3.6之前的版本中,如果您使用的glob方法中不包含任何通配符,则该函数很聪明:它知道您只能命中一次,因此可以将通配符简化为just os.path.isdiros.path.lexists(取决于path是否以结尾/)。
ShadowRanger

3
我的评论的第二部分(非通配符实际上不会迭代文件夹,也从未如此)确实意味着它是解决该问题的完美解决方案(比直接调用慢,os.path.isdir或者os.path.lexist因为它是一堆Python级别的函数调用和字符串)在确定有效路径可行之前进行操作,但不执行其他系统调用或I / O工作,这要慢几个数量级)。
ShadowRanger

154

这是检查文件是否存在的最简单方法。仅仅因为文件在您检查时存在并不保证在您需要打开文件时该文件就会存在。

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")

17
只要您打算访问该文件,就不会存在竞争条件,而与程序的构造方式无关。您的程序不能保证计算机上的另一个进程没有修改该文件。这就是埃里克·利珀特(Eric Lippert)所说的外生异常。您无法通过事先检查文件是否存在来避免它。
Isaac Supeene 2014年

@IsaacSupeene最佳实践是使(文件)操作的窗口尽可能小,然后进行适当的异常处理
un33k

145

Python 3.4+具有一个面向对象的路径模块:pathlib。使用这个新模块,您可以检查文件是否存在,如下所示:

import pathlib
p = pathlib.Path('path/to/file')
if p.is_file():  # or p.is_dir() to see if it is a directory
    # do stuff

您可以(通常应该)try/except在打开文件时仍然使用块:

try:
    with p.open() as f:
        # do awesome stuff
except OSError:
    print('Well darn.')

pathlib模块中包含很多很棒的东西:方便的globing,检查文件的所有者,更容易的路径连接等。值得一试。如果您使用的是旧版Python(2.6版或更高版本),则仍可以使用pip安装pathlib:

# installs pathlib2 on older Python versions
# the original third-party module, pathlib, is no longer maintained.
pip install pathlib2

然后按如下所示导入它:

# Older Python versions
import pathlib2 as pathlib

124

首选try语句。它被认为是更好的风格,并且避免了比赛条件。

不要相信我。这个理论有很多支持。这是一对:


3
请添加更好的资源以支持您的声明。
BlueTrin

11
引用的“避免竞争条件”(apple开发人员支持)链接不支持您的回答。它只涉及在设计不良的操作系统上使用包含敏感信息的临时文件,而这些操作系统不能通过受限权限正确地对临时文件/目录进行沙箱处理。无论如何使用try...except无助于解决问题。
jstine 2015年

这种方法的问题是,如果您有一段重要的代码(取决于不存在的文件),将其放在except:子句中将使在代码的这一部分中产生的异常会引起混乱的消息(在执行过程中引发第二个错误)处理)
。– Camion

119

如何在不使用try语句的情况下使用Python检查文件是否存在?

从Python 3.4开始可用,导入并实例化Path具有文件名的对象,然后检查is_file方法(请注意,对于指向常规文件的符号链接,此方法也返回True):

>>> from pathlib import Path
>>> Path('/').is_file()
False
>>> Path('/initrd.img').is_file()
True
>>> Path('/doesnotexist').is_file()
False

如果您使用的是Python 2,则可以从pypi,反向移植pathlib模块pathlib2,或者通过其他方式isfile从该os.path模块检查:

>>> import os
>>> os.path.isfile('/')
False
>>> os.path.isfile('/initrd.img')
True
>>> os.path.isfile('/doesnotexist')
False

现在,上面可能是这里最好的实用直接答案,但是有可能出现竞争状况(取决于您要完成的工作),并且底层实现使用try,而Python使用try在实现中无处不在。

因为Python使用 try随处,所以实际上没有理由避免使用它的实现。

但是此答案的其余部分试图考虑这些警告。

更长,更古怪的答案

自Python 3.4起可用,请使用中的新Path对象pathlib。请注意,这.exists不是很正确,因为目录不是文件(在Unix中,一切都是文件)。

>>> from pathlib import Path
>>> root = Path('/')
>>> root.exists()
True

所以我们需要使用is_file

>>> root.is_file()
False

这是有关的帮助is_file

is_file(self)
    Whether this path is a regular file (also True for symlinks pointing
    to regular files).

因此,让我们获得一个我们知道是文件的文件:

>>> import tempfile
>>> file = tempfile.NamedTemporaryFile()
>>> filepathobj = Path(file.name)
>>> filepathobj.is_file()
True
>>> filepathobj.exists()
True

默认情况下,NamedTemporaryFile该文件在关闭时删除(并且在没有更多引用时将自动关闭)。

>>> del file
>>> filepathobj.exists()
False
>>> filepathobj.is_file()
False

但是,如果深入研究实现,您将看到它的is_file使用try

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

比赛条件:为什么我们喜欢尝试

我们喜欢,try因为它避免了比赛条件。使用try,您只需尝试读取文件,期望它在那里,否则,您将捕获异常并执行有意义的后备行为。

如果要在尝试读取文件之前检查文件是否存在,并且可能要删除它,然后使用多个线程或进程,或者另一个程序知道该文件并可能将其删除,则可能会遇到以下风险:一个竞争条件,如果你检查它的存在,因为你是那么赛车的前打开状态(它的存在)的变化。

竞争条件很难调试,因为存在一个很小的窗口,在竞争窗口中它们可能导致您的程序失败。

但是,如果这是您的动力,则可以获取try使用的语句suppress上下文管理器。

在没有try语句的情况下避免出现竞争情况: suppress

Python 3.4为我们提供了suppress上下文管理器(以前称为ignore上下文管理器),它在较少的行中就语义上完全相同,而也(至少在表面上)满足了避免try语句的原始要求:

from contextlib import suppress
from pathlib import Path

用法:

>>> with suppress(OSError), Path('doesnotexist').open() as f:
...     for line in f:
...         print(line)
... 
>>>
>>> with suppress(OSError):
...     Path('doesnotexist').unlink()
... 
>>> 

对于较早的Python,您可以自己滚动suppress,但是如果没有,try它将比使用更加冗长。我确实相信这实际上是在try Python 3.4之前可以应用到Python的任何级别的唯一答案,因为它使用上下文管理器代替:

class suppress(object):
    def __init__(self, *exceptions):
        self.exceptions = exceptions
    def __enter__(self):
        return self
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            return issubclass(exc_type, self.exceptions)

尝试一下可能会更容易:

from contextlib import contextmanager

@contextmanager
def suppress(*exceptions):
    try:
        yield
    except exceptions:
        pass

不符合要求的其他选项“不尝试”:

文件

import os
os.path.isfile(path)

文档

os.path.isfile(path)

如果path是现有的常规文件,则返回True。这是继符号链接,这样既islink()并且isfile()可以为相同的路径是正确的。

但是,如果您检查此函数的来源,您会发现它确实使用了try语句:

# This follows symbolic links, so both islink() and isdir() can be true
# for the same path on systems that support symlinks
def isfile(path):
    """Test whether a path is a regular file"""
    try:
        st = os.stat(path)
    except os.error:
        return False
    return stat.S_ISREG(st.st_mode)
>>> OSError is os.error
True

它所做的就是使用给定的路径查看它是否可以获取统计信息OSError,然后捕获并检查它是否是文件(如果没有引发异常)。

如果您打算对文件进行某些操作,建议您使用try-except直接尝试它,以避免出现竞争情况:

try:
    with open(path) as f:
        f.read()
except OSError:
    pass

os.access

可用于Unix和Windows os.access,但要使用它,必须传递标志,并且不能区分文件和目录。这更用于测试真正的调用用户是否在提升的特权环境中具有访问权限:

import os
os.access(path, os.F_OK)

它也遭受与相同的比赛条件问题isfile。从文档

注意:在实际使用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()

避免使用 os.access。与上面讨论的较高级别的对象和功能相比,它是一个较低级别的功能,具有更多的用户错误机会。

批评另一个答案:

另一个答案是这样的os.access

就我个人而言,我更喜欢这个,因为它在后台调用了本机API(通过“ $ {PYTHON_SRC_DIR} /Modules/posixmodule.c”),但是它也为可能的用户错误打开了大门,并且它不像其他变体那样具有Python风格:

这个答案说它偏爱非Pythonic且容易出错的方法,没有理由。似乎鼓励用户使用不了解它们的低级API。

它还创建了一个上下文管理器,通过无条件返回True,它允许所有Exceptions(包括KeyboardInterruptSystemExit!)以静默方式传递,这是隐藏bug的好方法。

这似乎鼓励用户采用不良做法。


87
import os
#Your path here e.g. "C:\Program Files\text.txt"
#For access purposes: "C:\\Program Files\\text.txt"
if os.path.exists("C:\..."):   
    print "File found!"
else:
    print "File not found!"

导入os使您可以更轻松地在操作系统中导航和执行标准操作。

供参考,请参阅如何使用Python检查文件是否存在?

如果需要高级操作,请使用shutil


9
这个答案是错误的。os.path.exists对于非文件的内容(例如目录)返回true。这给出了误报。请参阅其他建议的答案os.path.isfile
克里斯·约翰逊

84

测试的文件和文件夹os.path.isfile()os.path.isdir()os.path.exists()

假定“路径”是有效路径,此表显示了每个函数对文件和文件夹返回的内容:

在此处输入图片说明

您还可以测试文件是否是os.path.splitext()用于获取扩展名的特定类型的文件(如果您还不知道的话)

>>> import os
>>> path = "path to a word document"
>>> os.path.isfile(path)
True
>>> os.path.splitext(path)[1] == ".docx" # test if the extension is .docx
True

72

在2016年,最好的方法仍然是使用os.path.isfile

>>> os.path.isfile('/path/to/some/file.txt')

或者在Python 3中,您可以使用pathlib

import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
    ...

3
请问:在检查中使用模块'pathlib'而不是python3中的模块'os'有什么好处?
Joko

3
pathlib是python的OOP路径解决方案。您可以用它做更多的事情。如果只需要检查存在性,那么优势就不会太大。
KaiBuxe

65

在try / except和之间似乎没有有意义的功能差异isfile(),因此您应该使用哪个才有意义。

如果要读取文件(如果存在),请执行

try:
    f = open(filepath)
except IOError:
    print 'Oh dear.'

但是,如果您只是想重命名文件(如果存在),因此不需要打开它,请执行

if os.path.isfile(filepath):
    os.rename(filepath, filepath + '.old')

如果要写入文件(如果不存在),请执行

# python 2
if not os.path.isfile(filepath):
    f = open(filepath, 'w')

# python 3, x opens for exclusive creation, failing if the file already exists
try:
    f = open(filepath, 'wx')
except IOError:
    print 'file already exists'

如果您需要文件锁定,那是另一回事。


3
这个答案是错误的。os.path.exists对于非文件的内容(例如目录)返回true。这给出了误报。请参阅其他建议的答案os.path.isfile
克里斯·约翰逊

6
在第三个示例中,我创建了一个以filepath正确的时间命名的链接,而BAM则覆盖了目标文件。你应该做open(filepath, 'wx')try...except块,以避免这个问题。
频谱

1
在第二个示例中,至少在Windows中,您将得到一个OSErrorif if if filepath + '.old'found:“在Windows上,如果dst已经存在,即使它是一个文件,也会引发OSError;在dst时可能无法实现原子重命名命名现有文件。”
Tom Myddeltyn '16

@TomMyddeltyn:从Python 3.3开始,os.replace可移植地执行目标文件的静默替换(与os.renameLinux行为相同)(仅当目标名称存在且为目录时,它才会出错)。因此,您只能使用2.x,但是Py3用户已经有好几年了。
ShadowRanger

rename示例中:仍应使用try/ 完成exceptos.rename(或os.replace在现代Python上)是原子的;进行检查然后重命名会引入不必要的竞争和其他系统调用。只是做try: os.replace(filepath, filepath + '.old') except OSError: pass
ShadowRanger

59

您可以尝试这样做(更安全):

try:
    # http://effbot.org/zone/python-with-statement.htm
    # 'with' is safer to open a file
    with open('whatever.txt') as fh:
        # Do something with 'fh'
except IOError as e:
    print("({})".format(e))

输出为:

([Errno 2]没有这样的文件或目录:'whatever.txt')

然后,根据结果,您的程序可以仅从那里继续运行,也可以编写代码以停止它。


18
原始问题要求使用不使用的解决方案try
rrs 2014年

5
这个答案错过了OP的重点。检查文件是否存在与检查是否可以打开文件不同。在某些情况下确实存在文件,但是由于多种原因,您无法打开该文件。
克里斯·约翰逊

51

尽管我总是建议使用tryexcept语句,但是这里有几种可能(我个人最喜欢使用os.access):

  1. 尝试打开文件:

    打开文件将始终验证文件是否存在。您可以像下面这样创建一个函数:

    def File_Existence(filepath):
        f = open(filepath)
        return True

    如果为False,它将在更高版本的Python中以未处理的IOError或OSError停止执行。要捕获异常,您必须使用tryexcept子句。当然,您总是可以try像这样使用except`语句(感谢hsandt 让我思考):

    def File_Existence(filepath):
        try:
            f = open(filepath)
        except IOError, OSError: # Note OSError is for later versions of Python
            return False
    
        return True
  2. 用途os.path.exists(path)

    这将检查您指定的内容是否存在。但是,它会检查文件目录,因此请注意如何使用它们。

    import os.path
    >>> os.path.exists("this/is/a/directory")
    True
    >>> os.path.exists("this/is/a/file.txt")
    True
    >>> os.path.exists("not/a/directory")
    False
  3. 用途os.access(path, mode)

    这将检查您是否有权访问该文件。它将检查权限。根据os.py文档,输入os.F_OK,它将检查路径的存在。但是,使用此方法会创建一个安全漏洞,因为有人可以使用检查权限到打开文件之间的时间来攻击您的文件。您应该直接打开文件,而不要检查其权限。(EAFPLBYP)。如果您以后不打算打开文件,而仅检查其存在,则可以使用它。

    无论如何,在这里:

    >>> import os
    >>> os.access("/is/a/file.txt", os.F_OK)
    True

我还应该提到,有两种方法将使您无法验证文件的存在。问题将是permission deniedno such file or directory。如果您发现IOError,请设置IOError as e(像我的第一个选项一样),然后键入print(e.args)以便希望确定问题。希望对您有所帮助!:)


51

日期:2017-12-04

每种可能的解决方案都已在其他答案中列出。

一种检查文件是否存在的直观且可争论的方法如下:

import os
os.path.isfile('~/file.md')  # Returns True if exists, else False
# additionaly check a dir
os.path.isdir('~/folder')  # Returns True if the folder exists, else False
# check either a dir or a file
os.path.exists('~/file')

我做了详尽的备忘单供您参考:

#os.path methods in exhaustive cheatsheet
{'definition': ['dirname',
               'basename',
               'abspath',
               'relpath',
               'commonpath',
               'normpath',
               'realpath'],
'operation': ['split', 'splitdrive', 'splitext',
               'join', 'normcase'],
'compare': ['samefile', 'sameopenfile', 'samestat'],
'condition': ['isdir',
              'isfile',
              'exists',
              'lexists'
              'islink',
              'isabs',
              'ismount',],
 'expand': ['expanduser',
            'expandvars'],
 'stat': ['getatime', 'getctime', 'getmtime',
          'getsize']}

37

如果该文件用于打开,则可以使用以下技术之一:

with open('somefile', 'xt') as f: #Using the x-flag, Python3.3 and above
    f.write('Hello\n')

if not os.path.exists('somefile'): 
    with open('somefile', 'wt') as f:
        f.write("Hello\n")
else:
    print('File already exists!')

更新

为了避免混淆,并根据我得到的答案,当前答案会找到具有给定名称的文件目录。


9
这个答案是错误的。os.path.exists对于非文件的内容(例如目录)返回true。这给出了误报。请参阅其他建议的答案os.path.isfile
克里斯·约翰逊

也有误报的问题。
Zorglub29 '18

docs.python.org/3/library/os.path.html#os.path.exists 至chris >> os.path.exists(path)的上述声明 >如果path指向现有路径或开放路径,则返回True文件描述符。对于断开的符号链接返回False。在某些平台上,即使未实际执行路径,如果未授予在请求的文件上执行os.stat()的权限,此函数也可能返回False。在版本3.3中更改:path现在可以是整数:如果它是打开的文件描述符,则返回True,否则返回False。在版本3.6中更改:接受类似路径的对象。
JayRizzo

36

另外,os.access()

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

作为R_OKW_OKX_OK标志,以测试权限(DOC)。


20
if os.path.isfile(path_to_file):
    try: 
        open(path_to_file)
            pass
    except IOError as e:
        print "Unable to open file"

引发异常被认为是程序中流控制的可接受且Pythonic的方法。考虑使用IOErrors处理丢失的文件。在这种情况下,如果文件存在但用户没有读取权限,则将引发IOError异常。

SRC:http//www.pfinn.net/python-check-if-file-exists.html


3
OP询问如何检查文件是否存在。文件可能存在,但您无法打开它。因此,使用打开文件作为代理来检查文件是否存在是不正确的:将具有假阴性。
克里斯·约翰逊

19

如果导入与NumPy已经用于其它用途,则没有必要导入其他库,例如pathlibospaths等。

import numpy as np
np.DataSource().exists("path/to/your/file")

这将根据其存在返回true或false。


18

您可以在不使用的情况下写下Brian的建议try:

from contextlib import suppress

with suppress(IOError), open('filename'):
    process()

suppress是Python 3.4的一部分。在较早的发行版中,您可以快速编写自己的隐匿:

from contextlib import contextmanager

@contextmanager
def suppress(*exceptions):
    try:
        yield
    except exceptions:
        pass

17

我是一个已经存在大约十年的软件包的作者,它的功能可以直接解决这个问题。基本上,如果您使用的是非Windows系统,则使用Popen可以访问find。但是,如果您使用的是Windows,它将find使用高效的文件系统walker 复制。

该代码本身不使用try块……除非确定操作系统,然后使您转向“ Unix”风格find或手动编译find。时序测试表明,try确定操作系统的速度更快,因此我确实在那儿使用了它(但没有其他地方)。

>>> import pox
>>> pox.find('*python*', type='file', root=pox.homedir(), recurse=False)
['/Users/mmckerns/.python']

还有文件

>>> print pox.find.__doc__
find(patterns[,root,recurse,type]); Get path to a file or directory

    patterns: name or partial name string of items to search for
    root: path string of top-level directory to search
    recurse: if True, recurse down from root directory
    type: item filter; one of {None, file, dir, link, socket, block, char}
    verbose: if True, be a little verbose about the search

    On some OS, recursion can be specified by recursion depth (an integer).
    patterns can be specified with basic pattern matching. Additionally,
    multiple patterns can be specified by splitting patterns with a ';'
    For example:
        >>> find('pox*', root='..')
        ['/Users/foo/pox/pox', '/Users/foo/pox/scripts/pox_launcher.py']

        >>> find('*shutils*;*init*')
        ['/Users/foo/pox/pox/shutils.py', '/Users/foo/pox/pox/__init__.py']

>>>

如果您愿意看一下的话,可以在这里找到实现:https : //github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190


17

检查文件或目录是否存在

您可以遵循以下三种方式:

注意1:os.path.isfile仅用于文件

import os.path
os.path.isfile(filename) # True if file exists
os.path.isfile(dirname) # False if directory exists

注意2:os.path.exists用于文件和目录

import os.path
os.path.exists(filename) # True if file exists
os.path.exists(dirname) #True if directory exists

pathlib.Path方法(包含在Python 3+中,可通过pip安装在Python 2中)

from pathlib import Path
Path(filename).exists()

16

再添加一个细微的变化,而其他变化未完全反映出来。

这将处理file_path存在None或为空字符串的情况。

def file_exists(file_path):
    if not file_path:
        return False
    elif not os.path.isfile(file_path):
        return False
    else:
        return True

根据Shahbaz的建议添加变体

def file_exists(file_path):
    if not file_path:
        return False
    else:
        return os.path.isfile(file_path)

根据Peter Wood的建议添加变体

def file_exists(file_path):
    return file_path and os.path.isfile(file_path):

3
if (x) return true; else return false;真的是公正return x。您的最后四行可以变成return os.path.isfile(file_path)。进行此操作时,整个功能可以简化为return file_path and os.path.isfile(file_path)
Shahbaz

你必须要小心return x的情况下if (x)。Python将认为空字符串为False,在这种情况下,我们将返回一个空字符串而不是布尔值。此函数的目的是始终返回bool。
马塞尔·威尔逊

1
真正。然而,在这种情况下,xos.path.isfile(..)那么它已经bool的。
Shahbaz

os.path.isfile(None)引发异常,这就是为什么我添加了if检查的原因。我可能可以将其包装在try / except中,但是我觉得这种方式更加明确。
马塞尔·威尔逊

3
return file_path and os.path.isfile(file_path)
彼得·伍德

15

这是用于Linux命令行环境的1行Python命令。我觉得这个非常好,因为我不是一个很酷的Bash家伙。

python -c "import os.path; print os.path.isfile('/path_to/file.xxx')"

我希望这是有帮助的。


6
在bash中单行签入:([ -f "${file}" ] && echo "file found" || echo "file not found"与相同if [ ... ]; then ...; else ...; fi)。
flotzilla 2015年

12

您可以使用Python的“ OS”库:

>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt") 
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False

5
这个答案是错误的。os.path.exists对于非文件的内容(例如目录)返回true。这给出了误报。请参阅其他建议的答案os.path.isfile
克里斯·约翰逊

@Chris Johnson,os.path.exists()函数检查系统中是否存在路径。PATH可以是目录或文件。在两种情况下都可以正常工作。请尝试使用一些示例
Pradip Das

因此,此答案有效。大。如果该路径不是文件路径。那是关于什么的问题吗?号
Debosmit Ray

这取决于。如果确定“文件”存在的目的是要找出路径是否已经存在(因此不是在不删除其他信息的情况下可以存储新数据的路径),那就exists很好。如果目标是确定打开一个可能存在的文件是否安全,则批评是有道理的,并且存在不够精确。可悲的是,OP没有指定哪个是期望的目标(并且可能不再这样做)。
starturtle

12

如何在不使用try语句的情况下检查文件是否存在?

在2016年,可以说这仍然是检查文件是否存在和是否是文件的最简单方法:

import os
os.path.isfile('./file.txt')    # Returns True if exists, else False

isfile实际上只是内部使用os.stat和内部使用的一种辅助方法stat.S_ISREG(mode)。这os.stat是一个较低层的方法,它将为您提供有关文件,目录,套接字,缓冲区等的详细信息。有关os.stat的更多信息

注意:但是,这种方法不会以任何方式锁定文件,因此您的代码可能容易受到“ 检查时间到使用时间 ”(TOCTTOU)错误的攻击

因此,引发异常被认为是程序中流控制的可接受且Pythonic的方法。而且,应该考虑使用IOErrors处理丢失的文件,而不是使用if语句(只是建议)。


9
import os.path

def isReadableFile(file_path, file_name):
    full_path = file_path + "/" + file_name
    try:
        if not os.path.exists(file_path):
            print "File path is invalid."
            return False
        elif not os.path.isfile(full_path):
            print "File does not exist."
            return False
        elif not os.access(full_path, os.R_OK):
            print "File cannot be read."
            return False
        else:
            print "File can be read."
            return True
    except IOError as ex:
        print "I/O error({0}): {1}".format(ex.errno, ex.strerror)
    except Error as ex:
        print "Error({0}): {1}".format(ex.errno, ex.strerror)
    return False
#------------------------------------------------------

path = "/usr/khaled/documents/puzzles"
fileName = "puzzle_1.txt"

isReadableFile(path, fileName)

@ j6m8是,如果文件可以通过process \ program \ thread读取,isReadableFile(path,fileName)则返回True
Khaled.K,2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.