python python判断文件是否存在 python存在 - 如何检查文件是否存在而没有例外?




15 Answers

如果你正在检查的原因是你可以做一些像if file_exists: open_it()那样的事情,那么尝试打开它会更安全。 检查然后打开风险,删除或移动文件或检查时以及尝试打开文件时。

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

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

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

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

从Python 3.4开始, pathlib模块提供了一种面向对象的方法(在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()

try:
    my_abs_path = my_file.resolve()
except FileNotFoundError:
    # doesn't exist
else:
    # exists
python校验文件是否存在 python创建文件

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




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



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"



2017/12/22

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

注意 :我要发布的每个Python标准库代码都属于3.5.3版(文档引用是特定于版本3 )。

问题陈述

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

可能解决方案

  1. [Python]:os.path。 existspath (还检查其他函数族成员,如os.path.isfileos.path.isdiros.path.lexists ,略有不同的行为)

    os.path.exists(path)
    

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

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

    • os.path - posixpath.pyntpath.py

      • genericpath.py ,line ~#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
        

    它只是围绕os.stat()一个try/exceptos.stat() os.stat() 。 所以,你的代码是try/except free,但是framestack中的代码是(至少) 一个这样的块。 这也适用于其他func( 包括 os.path.isfile )。

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

    • 它是处理路径的更高级(以及更多python ic)方式, 但是
    • 在引擎盖下,它完全相同pathlib.py ,line ~#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。 suppress* exceptions - 专门用于有选择地抑制异常


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

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

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


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

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

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

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

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

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

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

    Win特定):由于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因此相同的代码适用于Python3Python2 (尽管它们之间存在unicode相关的差异)
    • 虽然这针对的是一个非常具体的领域, 但在之前的任何答案中都没有提及


    LnxUbtu(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) )。 根据[man]:DLOPEN(3)

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

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

    最有可能的是,将依赖于上述方法之一(可能需要轻微的自定义)。
    一个例子(再次, Win特定) [GitHub]:Python for Windows(pywin32)扩展 ,它是WINAPI上Python包装器。

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

  6. 另一个(跛脚)解决方法( 获得 )是(我喜欢称之为) 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
      
    • LnxUbtu ):

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

底线

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

最后的说明

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



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



如何在不使用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意义上除了一切都是文件)。

>>> 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 ,您只需尝试读取您的文件,期望它在那里,如果没有,您将捕获异常并执行任何有意义的回退行为。

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

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

但如果这是你的动机,你可以使用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()
... 
>>> 

对于早期的Pythons,你可以滚动自己的suppress ,但不经过try将比使用更加冗长。 我相信这实际上是唯一没有在Python中可以应用于Python之前的任何级别使用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()都可以为true。

但是如果你检查这个函数的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:
    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 !)以静默方式传递,这是隐藏错误的好方法。

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




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

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

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



似乎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'

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




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

  1. 尝试打开文件:

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

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

    如果它为False,它将在更高版本的Python中以无错的IOError或OSError停止执行。 要捕获异常,必须使用try except子句。当然,你可以随时使用tryexcept`语句(感谢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)以便您可以确定您的问题。我希望它有所帮助! :)




另外,os.access()

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

存在R_OKW_OK以及X_OK用于测试权限的标志(doc)。







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

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

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




添加一个更微小的变化,这在其他答案中没有完全反映出来。

这将处理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):



检查文件或目录是否存在

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

注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()



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

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



Related