ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

G
Georgy

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

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

如果 path 是现有的常规文件,则返回 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

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

使用 os.path.exists 检查文件和目录:

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

使用 os.path.isfile 仅检查文件(注意:遵循符号链接):

os.path.isfile(file_path)

B
Boris Verkhovskiy

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

I
Iacchus
import os

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

n
null

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

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

通常,将变量命名为与方法名称相同的名称不是一个好习惯。
C
CristiFati

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

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

问题陈述:

检查文件(有争议:还有文件夹(“特殊”文件)?)存在不要使用try / except / else / finally块

可能的解决方案:

[Python 3]: os.path.exists(path) (还检查其他函数系列成员,如 os.path.isfile、os.path.isdir、os.path.lexists 的行为略有不同) os.path.exists(path ) 如果 path 引用现有路径或打开的文件描述符,则返回 True。对于损坏的符号链接返回 False。在某些平台上,如果未授予对请求的文件执行 os.stat() 的权限,即使路径物理存在,此函数也可能返回 False。一切都很好,但是如果遵循导入树: os.path - posixpath.py (ntpath.py) genericpath.py, line ~#20+ def exists(path): """测试路径是否存在。如果损坏则返回 False符号链接""" try: st = os.stat(path) except os.error: return False return True 这只是一个 try / except [Python 3] 周围的块: os.stat(path, *, dir_fd=None, follow_symlinks =真)。因此,您的代码是 try / except free,但在框架堆栈的较低位置(至少)有一个这样的块。这也适用于其他函数(包括 os.path.isfile)。 1.1。 [Python 3]:Path.is_file() 这是一种处理路径的更高级(和更 Pythonic)的方式,但在底层,它做的事情完全相同(pathlib.py,行 ~#1330):def is_file(self) : """ 此路径是否为常规文件(对于指向常规文件的符号链接也为 True)。 """ try: return S_ISREG(self.stat().st_mode) except OSError as e: if e.errno not in ( ENOENT, ENOTDIR): raise # Path 不存在或者是一个损坏的符号链接 # (参见 https://bitbucket.org/pitrou/pathlib/issue/12/) return False [Python 3]: With Statement Context Managers。任一: 创建一个: class Swallow: # Dummy examplespokened_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 # 只吞下 FileNotFoundError (不是例如 TypeError - 如果用户传递了错误的参数,如 None 或 float 或...)及其用法 - 我将复制 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]:with 语句指出:这允许常见的 try...except...finall y 使用模式被封装以方便重用。文件系统遍历函数(并搜索匹配项的结果)[Python 3]:os.listdir(path='.')(或 [Python 3]:os.scandir(path='.') 在 Python v3 上.5+, backport: [PyPI]: scandir) 在底层,两者都使用:Nix: [man7]: OPENDIR(3) / [man7]: READDIR(3) / [man7]: CLOSEDIR(3) Win: [ MS.Docs]:FindFirstFileW 函数/[MS.Docs]:FindNextFileW 函数/[MS.Docs]:FindClose 函数通过 [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.listdir (os.scandir 如果可用) [Python 3]: glob.iglob(pathname, *, recursive= False)(或其前身:glob.glob)本身似乎不是一个遍历函数(至少在某些情况下),但它仍然使用 os.listdir 由于这些迭代文件夹,(在大多数情况下)它们是对于我们的问题效率低下(有例外,如非通配符通配符 - 正如@ShadowRanger 指出的那样),所以我不会坚持使用它们。更不用说在某些情况下,可能需要文件名处理。 [Python 3]: os.access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True) 其行为接近 os.path.exists (实际上它更广泛,主要是因为第二个参数)用户如文档所述,权限可能会限制文件“可见性”: ...测试调用用户是否具有对路径的指定访问权限。模式应该是 F_OK 来测试路径的存在... os.access("/tmp", os.F_OK) 因为我也在 C 中工作,所以我也使用这个方法,因为在引擎盖下,它调用本机 API(再次,通过“${PYTHON_SRC_DIR}/Modules/posixmodule.c”),但它也为可能的用户错误打开了大门,而且它不像其他变体那样 Pythonic。因此,正如@AaronHall 正确指出的那样,除非您知道自己在做什么,否则不要使用它: Nix: [man7]: ACCESS(2) (!!!注意有关其使用可能引入的安全漏洞的说明!!!) Win: [MS.Docs]: GetFileAttributesW function 注意:调用本机 API 也可以通过 [Python 3]:ctypes - Python 的外部函数库,但在大多数情况下它更复杂。 (特定于 Win):由于 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 位 (AMD64)] 在 win32 上键入“帮助”、“版权”、“信用”或“许可证”以获取更多信息。 >>> 导入操作系统,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 注意:虽然这不是一个好习惯,但我在调用,但这只是为了清楚起见(它的值为 0)我使用 _waccess 以便相同的代码适用于 Python3 和 Python2(尽管它们之间存在 unicode 相关的差异)虽然这针对一个非常具体的领域,但没有提到在之前的任何答案中 Lnx (Ubtu (16 x64)) 对应物:Python 3.5.2 (default, Nov 17 2016, 17:05:23) [GCC 5.4.0 20160609] on linux 输入“帮助”, “版权”、“学分”或“许可”以获取更多信息。 >>> 导入操作系统,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") 可能(并且很可能会)因系统而异,无(或空字符串)可以传递给 CDLL 构造函数 (ctypes.CDLL(None).access(b"/tmp ", os.F_OK))。根据 [man7]: DLOPEN(3): If filename is NULL, 那么返回的句柄是主程序的。当给 dlsym() 时,这个句柄会导致在主程序中搜索一个符号,然后是程序启动时加载的所有共享对象,然后是 dlopen() 加载的所有共享对象,带有标志 RTLD_GLOBAL。主(当前)程序(python)与 libc 链接,因此将加载其符号(包括访问权限) 这必须小心处理,因为 main、Py_Main 和(所有)其他函数都可用;调用它们可能会产生灾难性影响(对当前程序) 这也不适用于 Win(但这并不是什么大不了的事,因为 msvcrt.dll 位于“%SystemRoot%\System32”中,它位于 %PATH% by默认)。我想更进一步并在 Win 上复制此行为(并提交补丁),但事实证明,[MS.Docs]:GetProcAddress 函数仅“看到”导出的符号,因此除非有人在主可执行文件中声明这些函数作为 __declspec(dllexport) (为什么地球上的普通人会这样做?),主程序是可加载的,但几乎无法使用安装一些具有文件系统功能的第三方模块很可能会依赖上述方法之一(也许与轻微的定制)。一个示例是(同样,特定于 Win)[GitHub]:mhammond/pywin32 - Python for Windows (pywin32) Extensions,它是 WINAPI 上的 Python 包装器。但是,由于这更像是一种解决方法,所以我在这里停下来。另一个(蹩脚的)解决方法(gainarie)是(我喜欢这样称呼它)系统管理员方法:使用 Python 作为包装器来执行 shell 命令 Win: (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 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 "导入操作系统;打印(os.system('ls \"/tmp.notexist\" > /dev/null 2>&1'))" 512

底线:

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

最后说明:

我会尽量保持最新,欢迎任何建议,我会将任何有用的东西纳入答案


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 工作,这要慢几个数量级)。
H
Honest Abe

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

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

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 打开文件,并且没有时间窗口。
R
Russia Must Remove Putin

如何在不使用 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 使用 {1 } 在其实现中无处不在。

因为 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 上下文管理器),它在语义上用更少的行完成完全相同的事情,同时也(至少在表面上)满足了避免使用 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 之前的任何级别均不使用 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

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

文件

import os
os.path.isfile(path)

来自 docs

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

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

这遵循符号链接,因此 islink() 和 isdir() 都可以为真 # 对于支持符号链接的系统上的相同路径 def isfile(path): """测试路径是否为常规文件""" 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

操作系统访问

可用于 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" # 不是权限错误。引发 else: with fp: return fp.read()

避免使用 os.access。它是一个低级函数,比上面讨论的高级对象和函数有更多的用户错误机会。

对另一个答案的批评:

另一个答案是关于 os.access 的:

就个人而言,我更喜欢这个,因为在底层,它调用原生 API(通过“${PYTHON_SRC_DIR}/Modules/posixmodule.c”),但它也为可能的用户错误打开了大门,而且它不像其他变体那样 Pythonic :

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

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

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


H
Honest Abe

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

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

样式:http://allendowney.com/sd/notes/notes11.txt 的“处理异常情况”部分

避免竞争条件


请添加更好的资源来支持您的陈述。
引用的避免竞争条件(苹果开发支持)链接不支持您的答案。它仅涉及在设计不佳的操作系统上使用包含敏感信息的临时文件,这些操作系统无法通过受限权限正确沙箱临时文件/目录。无论如何,使用 try...except 无助于解决 那个 问题。
这种方法的问题在于,如果您有一段重要的代码取决于不存在的文件,将其放在 except: 子句中会使您的这部分代码中出现的异常会引发令人困惑的消息(第二在第一个处理过程中出现错误。)
k
karlzafiris
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 的其他答案。
T
Tom Fuller

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

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

https://i.stack.imgur.com/tOs9p.png

您还可以使用 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

M
Memin

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+,这个库使您在处理文件和文件夹时的生活更加轻松,而且它很好用,这里有更多关于它的文档({1 })。

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

所以会变成

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()
P
Peter Mortensen

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

pathlib 是 python 的路径 OOP 解决方案。你可以用它做更多的事情。如果你只需要检查存在,优势就没有那么大了。
c
chad

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 已经存在,即使它是一个文件也会引发 OSError;可能无法当 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
P
Peter Mortensen

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

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的重点。检查文件是否存在与检查是否可以打开它是不同的。在某些情况下,文件确实存在,但由于各种原因,您无法打开它。
A
Azat Ibrakov

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

P
Peter Mortensen

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

尝试打开文件:打开文件将始终验证文件是否存在。你可以像这样创建一个函数: def File_Existence(filepath): f = open(filepath) return True 如果它是 False,它将在更高版本的 Python 中以未处理的 IOError 或 OSError 停止执行。要捕获异常,您必须使用 try except 子句。当然,你总是可以像这样使用 try except` 语句(感谢 hsandt 让我思考): def File_Existence(filepath): try: f = open(filepath) except IOError, OSError: # Note OSError is for later versions Python 返回 False 返回 True 使用 os.path.exists(path):这将检查您指定的内容是否存在。但是,它会检查文件和目录,因此请注意您如何使用它。导入 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),这样您就可以确定您的问题。我希望它有帮助! :)


T
Tshilidzi Mudau

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

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 版更改: 接受类似路径的对象。
a
armatita

此外,os.access()

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

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


P
Pedro Lobito
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询问如何检查文件是否存在。文件可能存在,但您无法打开它。因此,使用打开文件作为检查文件是否存在的代理是不正确的:会有误报。
J
JayRizzo

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

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

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


P
Peter Mortensen

您可以在没有 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

A
Ali Hallaji

检查文件或目录是否存在

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

Note1: os.path.isfile 仅用于文件

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

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

M
Marcel Wilson

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

这将处理 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)
P
Peter Mortensen

我是一个已经存在了大约 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


L
Love and peace - Joe Codeswell

这是用于 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 :) 我不同意。
P
Peter Mortensen

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

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

这个答案是错误的。 os.path.exists 对于不是文件的事物(例如目录)返回 true。这会产生误报。请参阅推荐 os.path.isfile 的其他答案。
@Chris Johnson, os.path.exists() 函数检查系统中是否存在路径。 PATH 可能是一个目录或文件。它在这两种情况下都可以正常工作。请尝试一些例子
所以,这个答案有效。伟大的。如果路径不是文件的路径。这就是问题所在吗?不。
这取决于。如果确定“文件”是否存在的目的是找出路径是否已经存在(因此不是在不删除其他信息的情况下可以存储新数据的路径),那么 exists 就可以了。如果目标是确定打开可能存在的文件是否安全,那么批评是有道理的并且存在不够精确。可悲的是,OP 没有指定哪个是期望的目标(并且可能不会再这样做了)。
P
Peter Mortensen

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

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

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

isfile 实际上只是一个在内部使用 os.statstat.S_ISREG(mode) 的辅助方法。此 os.stat 是一种较低级别的方法,它将为您提供有关文件、目录、套接字、缓冲区等的详细信息。 More about os.stat here

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

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