如何检查文件是不是存在无异常?

Posted

技术标签:

【中文标题】如何检查文件是不是存在无异常?【英文标题】:How do I check whether a file exists without exceptions?如何检查文件是否存在无异常? 【发布时间】:2010-09-10 02:47:26 【问题描述】:

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

【问题讨论】:

要检查 Path 对象是否存在,而不管它是文件还是目录,请使用my_path.exists() my_path.exists() 是不够的。 my_path.is_file() 会告诉你它是否是一个文件(可能适合阅读)。但是如果你想创建文件,你还必须检查exists,以便排除文件系统中会导致失败的目录或其他非文件内容。 【参考方案1】:

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

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

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

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

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

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

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

您也可以在try 块中使用resolve(strict=True)

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

【讨论】:

关于第一条评论(如果在打开之前检查,请使用“try”)不幸的是,如果您想打开以确保它之前存在,这将不起作用,因为如果不存在,将创建“a”模式。 请注意,FileNotFoundError 是在 Python 3 中引入的。如果您还需要支持 Python 2.7 和 Python 3,则可以使用 IOError 代替(FileNotFoundError 的子类)***.com/a/21368457/1960959 @makapuf 你可以打开它进行“更新”(open('file', 'r+'))然后搜索到最后。 等等,所以pathlib2 pathlib? pathlib 是针对 python3 的,对吧?我一直在使用 pathlib2 认为它更出色。 @kyrill:打开文件进行追加与打开文件进行写入并搜索到末尾是不同的:当您有并发写入者时,它们将在没有'a' 的情况下相互覆盖。【参考方案2】:

你有os.path.exists函数:

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

这将为文件和目录返回True,但您可以改为使用

os.path.isfile(file_path)

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:
import os

if os.path.isfile(filepath):
   print("File exists")

【讨论】:

【参考方案5】:

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

【讨论】:

有多个条件,其中一些是多余的,是less清晰明确的。 这也是多余的。如果文件不存在,os.access() 将返回 false。 @EJP 在 linux 文件可以存在但不能访问。 既然你是import os,你不需要再次import os.path,因为它已经是os的一部分。如果您只想使用来自os.path 而不是来自os 本身的函数,则只需要导入os.path 来导入较小的东西,但是当您使用os.accessos.R_OK 时,第二个导入是不需要。 检查用户是否有读取文件的权限非常专业。通常数据在开发期间位于本地驱动器上,而在生产期间位于网络共享上。那么这可能会导致这种情况。此外,代码非常清晰、可读和明确。【参考方案6】:
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

【讨论】:

一般来说,将变量命名为与方法名称相同的名称不是一个好习惯。【参考方案7】:

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

注意:我要发布的每一段Python标准库代码都属于3.5.3版本。 p>

问题陈述

    检查文件(可论证:还有文件夹(“特殊”文件)?)存在 不要使用 try / except / else / 终于

可能的解决方案

    [Python 3]: os.path.exists(path)(也可以查看其他函数家族成员,例如 os.path.isfileos.path.isdiros.path.lexists 以了解略有不同的行为)

    os.path.exists(path)
    

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

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

    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
    

    这只是 [Python 3]: os.stat(path, *, dir_fd=None, follow_symlinks=True) 周围的 try / except 块。因此,您的代码 try / except 是免费的,但在框架堆栈的较低位置(至少)一个这样的块。这也适用于其他函数(包括 os.path.isfile)。

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

    这是一种处理路径的更高级(并且更 pythonic)的方式,但是

    在底层,它完全相同做同样的事情(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
    

    [Python 3]: With Statement Context Managers。要么:

    创建一个:

    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.suppress(*exceptions) - 专门设计用于选择性地抑制异常

    但是,它们似乎是 try / except / else / finally 阻塞,正如[Python 3]: The with statement 所说:

    这允许封装常见的try...except...finally 使用模式以方便重用。

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

    [Python 3]: os.listdir(path='.')(或 Python v3.5+ 上的 [Python 3]: os.scandir(path='.'),反向移植:[PyPI]: scandir)

    在引擎盖下,两者都使用:

    尼克斯:[man7]: OPENDIR(3) / [man7]: READDIR(3) / [man7]: CLOSEDIR(3) :[MS.Docs]: FindFirstFileW function / [MS.Docs]: FindNextFileW function / [MS.Docs]: FindClose function

    通过[GitHub]: python/cpython - (master) cpython/Modules/posixmodule.c

    使用scandir() 代替listdir() 可以显着提高还需要文件类型或文件属性信息的代码的性能,因为如果操作系统在扫描目录时提供os.DirEntry 对象会公开此信息。所有os.DirEntry 方法都可以执行系统调用,但is_dir() 和is_file() 通常只需要对符号链接进行系统调用; os.DirEntry.stat() 在 Unix 上总是需要一个系统调用,但在 Windows 上只需要一个用于符号链接。

    [Python 3]: os.walk(top, topdown=True, onerror=None, followlinks=False) 它使用os.listdiros.scandir 可用时) [Python 3]: glob.iglob(pathname, *, recursive=False)(或其前身:glob.glob) 似乎不是一个遍历函数本身(至少在某些情况下),但它仍然使用os.listdir

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

    [Python 3]: os.access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True) 其行为接近os.path.exists(实际上它更宽,主要是因为 2nd 参数)

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

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

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

    由于我也在 C 中工作,所以我也使用此方法,因为在底层,它调用 native APIs(同样,通过 "$PYTHON_SRC_DIR/Modules/posixmodule.c"),但它也为可能的用户错误打开了大门,而且它不像 Python em>ic 作为其他变体。所以,正如@AaronHall 正确指出的那样,除非你知道自己在做什么,否则不要使用它:

    Nix:[man7]: ACCESS(2)(!!!注意关于安全漏洞它的使用可能会引入!!!) :[MS.Docs]: GetFileAttributesW function

    注意:也可以通过[Python 3]: ctypes - A foreign function library for Python 调用原生API,但在大多数情况下会更复杂。

    Win 特定):自 vcruntime* (msvcr*) .dll em> 还导出了一个 [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 它们之间的相关差异) 虽然这针对的是一个非常具体的领域,之前的任何答案中都没有提及

    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"/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,因此它的符号(包括access)将被加载 这必须小心处理,因为像 mainPy_Main 和(所有)其他函数都是可用的;调用它们可能会产生灾难性影响(对当前程序) 这也不适用于 Win(但这没什么大不了的,因为 msvcrt.dll 位于 "%SystemRoot%\System32 " 默认在 %PATH% 中)。我想更进一步并在 Win 上复制这种行为(并提交补丁),但事实证明,[MS.Docs]: GetProcAddress function 只“看到”导出符号,所以除非有人将主可执行文件中的函数声明为__declspec(dllexport)(为什么普通人会这样做?),主程序是可加载的,但几乎无法使用

    安装一些具有文件系统功能的第三方模块

    很可能会依赖上述方法之一(可能会进行轻微的自定义)。 一个例子是(同样,Win 特定的)[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions,它是 WINAPIs 之上的 Python 包装器。

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

    另一个(蹩脚的)解决方法(gainarie)是(我喜欢这样称呼它)sysadmin 方法:使用 Python 作为执行shell命令的包装器

    (py35x64_test) e:\Work\Dev\***\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\***\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
    

    Nix (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
    

底线

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

最后说明

我会尽量保持最新,欢迎提出任何建议,我会将任何有用的信息纳入答案

【讨论】:

你能详细说明一下这个说法吗? “虽然这不是一个好习惯,但我在调用中使用了 os.F_OK,但这只是为了清楚起见(其值为 0)” @sk8asd123:在评论中很难做到这一点:通常,最好将常量与它们一起使用的函数一起使用。这适用于使用定义相同常量的多个模块时,因为有些可能不是最新的,最好让函数和常量保持同步。当使用 ctypes(直接调用函数)时,我应该定义常量(来自 MSDN),或者根本不使用常量。这只是我使用的一个指南,在 99.9% 中它可能没有任何区别(在功能上)。 @CristiFati:从 3.6 开始,glob.iglob (and glob.glob as well) are based on os.scandir,所以现在很懒;要在 10M 个文件的目录中获得第一次点击,您只需扫描直到第一次点击。甚至在 3.6 之前,如果您使用不带任何通配符的 glob 方法,该功能很智能:它知道您只能点击一次,因此 it simplifies the globbing to just os.path.isdir or os.path.lexists(取决于路径是否以 / 结尾)。 我评论的第二部分(非通配符通配符实际上不会迭代文件夹,并且从来没有)确实意味着它是解决问题的完美有效解决方案(比直接调用 os.path.isdiros.path.lexist 因为它是一堆 Python 级别的函数调用和字符串操作,然后才决定有效的路径是可行的,但没有额外的系统调用或 I/O 工作,这要慢几个数量级)。【参考方案8】:

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 模块中有很多很酷的东西:方便的通配符、检查文件的所有者、更简单的路径连接等。值得一试。如果您使用的是较旧的 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

【讨论】:

可以使用pathlib.Path.exists,比is_file覆盖的案例更多【参考方案9】:

这是检查文件是否存在的最简单方法。只是因为文件在您检查时已经存在,并不能保证当您需要打开它时它会在那里。

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

【讨论】:

只要您打算访问该文件,竞争条件确实存在,无论您的程序是如何构造的。您的程序不能保证计算机上的另一个进程没有修改该文件。这就是 Eric Lippert 所说的 exogenous exception。您无法通过事先检查文件的存在来避免它。 @IsaacSupeene 最佳做法是让(文件)操作的窗口尽可能小,然后进行适当的异常处理 最好是用try+catch打开文件,没有时间窗口。【参考方案10】:

如何在不使用 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 pathlib2 反向移植 pathlib 模块,或者从 os.path 模块检查 isfile

>>> 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 起可用,使用 pathlib 中的新 Path 对象。请注意,.exists 不太正确,因为目录不是文件(除了在 unix 意义上 everything 是文件)。

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

如果您深入研究the implementation,您会发现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,您只需尝试读取您的文件,并期望它存在,如果没有,您会捕获异常并执行任何有意义的回退行为。

如果您想在尝试读取文件之前检查它是否存在,并且您可能正在删除它,然后您可能正在使用多个线程或进程,或者另一个程序知道该文件并可以将其删除 - 您可能会冒险竞态条件如果你检查它存在的机会,因为你然后竞速在它的条件(它的存在)改变之前打开它。

竞态条件很难调试,因为有一个非常小的窗口可能会导致您的程序失败。

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

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

Python 3.4 为我们提供了 suppress 上下文管理器(以前的 ignore 上下文管理器),它在语义上以更少的行数完成完全相同的事情,同时(至少在表面上)满足了避免@987654359 的原始要求@声明:

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 会比使用更冗长。我确实相信这实际上是在 Python 3.4 之前的任何级别都没有使用 try 的唯一答案,因为它使用上下文管理器代替:

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

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

isfile

import os
os.path.isfile(path)

来自docs:

os.path.isfile(path)

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

但是如果你检查这个函数的source,你会发现它确实使用了一个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 相同的竞争条件问题。来自docs:

注意: 使用 access() 检查用户是否被授权,例如打开一个文件 在实际这样做之前使用 open() 创建一个安全漏洞,因为 用户可能会利用检查和检查之间的短时间间隔 打开文件来操作它。最好使用 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”),但它也为可能的用户错误打开了一扇门,而且它不像 Pythonic作为其他变体:

这个答案说它更喜欢非 Pythonic、容易出错的方法,没有任何理由。它似乎鼓励用户在不了解它们的情况下使用低级 API。

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

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

【讨论】:

【参考方案11】:

更喜欢 try 语句。它被认为是更好的风格并避免了竞争条件。

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

风格:http://allendowney.com/sd/notes/notes11.txt 的“处理异常情况”部分 Avoiding Race Conditions

【讨论】:

请添加更好的资源来支持您的陈述。 引用的避免竞争条件(苹果开发支持)链接不支持您的答案。它仅涉及在设计不佳的操作系统上使用包含敏感信息的临时文件,这些操作系统无法通过受限权限正确沙箱临时文件/目录。无论如何,使用try...except 无助于解决那个问题。 这个方法的问题是,如果你有一段重要的代码依赖于不存在的文件,把它放在except: 子句中会使你的这部分出现异常代码将引发令人困惑的消息(在处理第一个错误期间引发第二个错误。)【参考方案12】:
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 可以更轻松地使用您的操作系统进行导航和执行标准操作。

参考参见How to check whether a file exists using Python?

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

【讨论】:

这个答案是错误的。 os.path.exists 对于不是文件的东西(例如目录)返回 true。这会产生误报。查看推荐os.path.isfile的其他答案。【参考方案13】:

使用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

【讨论】:

【参考方案14】:

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():
    ...

【讨论】:

请问:在 python3 中使用模块 'pathlib' 而不是模块 'os' 进行这种检查有什么好处? pathlib 是 python 的路径 OOP 解决方案。你可以用它做更多的事情。如果只需要检查存在,优势就没有那么大了。【参考方案15】:

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'

如果您需要文件锁定,那就另当别论了。

【讨论】:

这个答案是错误的。 os.path.exists 对于不是文件的东西(例如目录)返回 true。这会产生误报。查看推荐os.path.isfile的其他答案。 在您的第三个示例中,我使用正确的时间创建了一个名为filepath 的链接,然后BAM 覆盖目标文件。您应该在 try...except 块中执行 open(filepath, 'wx') 以避免该问题。 在你的第二个例子中,至少在 Windows 中,如果 filepath + '.old' 已经存在,你会得到一个 OSError:“在 Windows 上,如果 dst 已经存在,即使它是一个文件;当 dst 命名现有文件时,可能无法实现原子重命名。" @TomMyddeltyn: As of Python 3.3, os.replace 可移植地执行目标文件的静默替换(它与os.rename 的 Linux 行为相同)(仅当目标名称存在并且是目录时才会出错)。所以你被困在 2.x 上,但 Py3 用户多年来一直有一个不错的选择。 rename 示例上:仍应使用try/except 完成。 os.rename(或现代 Python 上的 os.replace)是原子的;使其检查然后重命名会引入不必要的竞争和额外的系统调用。就做try: os.replace(filepath, filepath + '.old') except OSError: pass【参考方案16】:

你可以试试这个(更安全):

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

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

【讨论】:

原问题要求的解决方案不使用try 这个答案错过了 OP 的重点。检查文件是否存在与检查是否可以打开它不同。在某些情况下,文件确实存在,但由于各种原因,您无法打开它。【参考方案17】:

TL;DR 答案是:pathlib 模块——一行代码——

Pathlib 可能是几乎所有文件操作的最现代和最方便的方式。对于文件文件夹的存在,一行代码就足够了。

from pathlib import Path

if Path("myfile.txt").exists(): # works for both file and folders
    # do your cool stuff...

pathlib 模块是在Python 3.4 中引入的,所以你需要有 Python 3.4+,这个库让你在处理文件和文件夹时更轻松,而且它很好用,这里有更多关于它的文档(https://docs.python.org/3/library/pathlib.html)。

顺便说一句,如果要重用路径,最好将其分配给变量

会变成这样

from pathlib import Path

p = Path("loc/of/myfile.txt")
if p.exists(): # works for both file and folders
    # do stuffs...
#reuse 'p' if needed.

【讨论】:

请注意,如果文件不存在但文件路径存在,则返回 True。如果你真的有兴趣询问文件是否存在,你应该使用 p.is_file()【参考方案18】:

日期: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']

【讨论】:

【参考方案19】:

虽然我总是推荐使用tryexcept 语句,但这里有一些可能性供您使用(我个人最喜欢使用os.access):

    尝试打开文件:

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

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

    如果为 False,它将停止执行并出现未处理的 IOError 或更高版本的 Python 中的 OSError。要捕获异常, 您必须使用 try except 子句。当然,你总是可以 像这样使用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
    

    使用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
    

    使用os.access(path, mode):

    这将检查您是否有权访问该文件。它将检查权限。根据 os.py 文档,输入os.F_OK,它将检查路径是否存在。但是,使用它会造成安全漏洞,因为有人可以使用检查权限和打开文件之间的时间来攻击您的文件。您应该直接打开文件而不是检查其权限。 (EAFP 与 LBYP)。如果你以后不打算打开文件,只检查它的存在,那么你可以使用它。

    不管怎样,这里:

    >>> 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),这样您就可以确定您的问题。我希望它有帮助! :)

【讨论】:

【参考方案20】:

最简单的方法是使用

import os

if os.path.exists(FILE):
  # file exists
  pass
else:
  # file does not exists
  pass

来自 os 库,而 FILE 是相对路径。在 Windows 中,这可能或许多不起作用,您可能必须通过执行 os.path.exists(os.path.join(os.path.abspath('./'), FILE)) 来使用绝对路径,其中 FILE 仍然是相对路径加上文件名

【讨论】:

【参考方案21】:

另外,os.access():

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

作为 R_OKW_OKX_OK 的标志来测试权限 (doc)。

【讨论】:

【参考方案22】:

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

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!')

更新

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

【讨论】:

这个答案是错误的。 os.path.exists 对于不是文件的东西(例如目录)返回 true。这会产生误报。查看推荐os.path.isfile的其他答案。 也遇到了误报问题。 docs.python.org/3/library/os.path.html#os.path.exists 来自 chris 的上述语句 >>os.path.exists(path) > 如果 path 引用现有路径或打开的文件描述符,则返回 True。对于损坏的符号链接返回 False。在某些平台上,如果未授予对请求的文件执行 os.stat() 的权限,即使路径物理存在,此函数也可能返回 False。在 3.3 版更改:路径现在可以是整数:如果它是打开的文件描述符,则返回 True,否则返回 False。在 3.6 版更改:接受类似路径的对象。【参考方案23】:

你可以使用 os.path.exists() :

import os
print(os.path.exists("file"))

希望对你有帮助:D

【讨论】:

【参考方案24】:
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

【讨论】:

OP 询问如何检查文件是否存在。文件可能存在,但您无法打开它。因此,使用打开文件作为检查文件是否存在的代理是不正确的:会有误报。【参考方案25】:

如果您已经出于其他目的导入了 NumPy,则无需导入其他库,例如 pathlibospaths 等。

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

这将根据其存在返回真或假。

【讨论】:

【参考方案26】:

您可以在没有 try: 的情况下编写 Brian 的建议。

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

【讨论】:

【参考方案27】:

检查文件或目录是否存在

您可以按照以下三种方式:

注意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+ 中,可通过 Python 2 的 pip 安装)

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

【讨论】:

【参考方案28】:

添加另一个未完全反映在其他答案中的细微变化。

这将处理file_pathNone 或空字符串的情况。

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

【讨论】:

if (x) return true; else return false; 真的只是return x。你的最后四行可以变成return os.path.isfile(file_path)。当我们这样做的时候,整个函数可以简化为return file_path and os.path.isfile(file_path) if (x) 的情况下,您必须小心return x。 Python 将考虑一个空字符串 False 在这种情况下我们将返回一个空字符串而不是一个布尔值。此函数的目的是始终返回 bool。 是的。然而,在这种情况下,xos.path.isfile(..),所以它已经是布尔值了。 os.path.isfile(None) 引发异常,这就是我添加 if 检查的原因。我可能只是将它包装在 try/except 中,但我觉得这样更明确。 return file_path and os.path.isfile(file_path)【参考方案29】:

我是一个已经存在了大约 10 年的包的作者,它具有直接解决这个问题的功能。基本上,如果您在非 Windows 系统上,它使用Popen 访问find。但是,如果您使用的是 Windows,它会使用高效的文件系统遍历器复制 find

代码本身不使用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

【讨论】:

【参考方案30】:

这是用于 Linux 命令行环境的 1 行 Python 命令。我觉得这很方便,因为我不是那么热门的 Bash 人。

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

我希望这会有所帮助。

【讨论】:

bash 中的单行签入:[ -f "$file" ] && echo "file found" || echo "file not found"(与if [ ... ]; then ...; else ...; fi 相同)。 Python 对于命令行上的这项工作来说是一个完全错误的工具。 嗨@ruohola :) 我不同意。

以上是关于如何检查文件是不是存在无异常?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查文件是不是存在无异常?

如何检查文件是不是存在无异常?

赛普拉斯:检查元素是不是存在无异常

如何使用 fstream::open() 检查 C++ 中是不是存在文件

Nightwatchjs:如何在不创建错误/失败/异常的情况下检查元素是不是存在

检查目录是不是存在和权限[重复]