Vraag Hoe controleer ik of een bestand bestaat?


Hoe zie ik of een bestand bestaat of niet, zonder de try uitspraak?


4347
2017-09-17 12:55


oorsprong


antwoorden:


Als de reden die u controleert, is zodat u zoiets kunt doen if file_exists: open_it(), het is veiliger om een ​​te gebruiken try rond de poging om het te openen. Het controleren en vervolgens openen van het risico is dat het bestand wordt verwijderd of verplaatst of dat er iets tussenin staat wanneer u het aanvinkt en wanneer u het probeert te openen.

Als u niet van plan bent het bestand onmiddellijk te openen, kunt u gebruiken os.path.isfile

terugkeer True als pad een bestaand regulier bestand is. Dit volgt op symbolische koppelingen, dus beide islink () en isfile () kan waar zijn voor hetzelfde pad.

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

als je zeker wilt weten dat het een bestand is.

Te beginnen met Python 3.4, de pathlib module biedt een object-georiënteerde aanpak (backported naar pathlib2 in Python 2.7):

from pathlib import Path

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

Ga als volgt te werk om een ​​map te controleren:

if my_file.is_dir():
    # directory exists

Controleren of een Path object bestaat onafhankelijk van het feit of het een bestand of directory is, gebruik exists():

if my_file.exists():
    # path exists

Je kan ook gebruiken resolve() in een try blok:

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

3949
2017-09-17 12:57



Jij hebt de os.path.exists functie:

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

Dit komt terug True voor zowel bestanden als mappen, maar u kunt in plaats daarvan gebruiken

os.path.isfile(file_name)

om te testen of het specifiek een bestand is. Het volgt symlinks.


1624
2017-09-17 12:57



anders isfile(), exists() zal terugkeren True voor mappen.
Dus afhankelijk van of je alleen gewone bestanden of mappen wilt, gebruik je isfile() of exists(). Hier is een eenvoudige REPL-uitvoer.

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

835
2017-09-17 15:01



import os.path

if os.path.isfile(filepath):

467
2017-09-17 12:55



Gebruik os.path.isfile() met 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"

220
2018-01-16 05:57



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

209
2017-09-17 12:56



Dit is de eenvoudigste manier om te controleren of een bestand bestaat. Net omdat het bestand bestond toen u aanvinkt niet garantie dat het er zal zijn wanneer je het moet openen.

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

138
2018-06-27 13:38



2017/12/22:

Hoewel bijna elke mogelijke manier is opgesomd in (ten minste één van) de bestaande antwoorden (bijv. Python 3.4 specifieke dingen zijn toegevoegd), ik zal proberen alles samen te groeperen.

Notitie: elk stukje Python standaard bibliotheekcode die ik ga plaatsen, behoort tot de versie 3.5.3 (doc citaten zijn versie 3 specifiek).

Probleemstelling:

  1. Controleer bestand (betwistbaar: ook map ("speciaal" bestand)?) bestaan
  2. Niet gebruiken try / except / else / finally blokken

Mogelijke oplossingen:

  1. [Python]: os.path.bestaat(pad) (controleer ook andere functie familieleden zoals os.path.isfile, os.path.isdir, os.path.lexists voor iets ander gedrag)

    os.path.exists(path)
    

    terugkeer True als pad verwijst naar een bestaand pad of een open bestandsdescriptor. Komt terug False voor gebroken symbolische koppelingen. Op sommige platforms kan deze functie terugkeren False als toestemming niet wordt verleend om uit te voeren os.stat () op het gevraagde bestand, zelfs als het pad bestaat fysiek.

    Allemaal goed, maar als je de importboom volgt:

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

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

    het is gewoon een try/except blokkeren rond [Python]: os.stat(path, *, dir_fd = Geen, follow_symlinks = True). Dus je code is try/except gratis, maar lager in de framestack is er (tenminste) een zo'n blok. Dit geldt ook voor andere functies (inclusief  os.path.isfile).

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

    • Het is een liefhebber (en meer Pythonic) manier om paden te verwerken, maar
    • Onder de motorkap, het doet precies hetzelfde (pathlib.py, lijn ~ # 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]: met Statement Context Managers. Een van beide:

    • Creëer er een:

      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 ...)
      
      • En het gebruik ervan - ik zal de isfile gedrag (merk op dat dit alleen voor demonstratiedoeleinden is, wel doen niet poging om dergelijke code te schrijven voor productie):

        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
        
    • Gebruik [Python]: contextlib.onderdrukken(*uitzonderingen) - welke was specifiek Geschikt voor het selectief onderdrukken van uitzonderingen


    Maar ze lijken omhullend te zijn try/except/else/finally blokken, zoals [Python]: De met uitspraak luidt als volgt:

    Dit maakt gemeenschappelijk proberen...behalve...Tenslotte gebruikspatronen die moeten worden ingekapseld voor gemakkelijk hergebruik.

  3. Bestandssysteem doorlopende functies (en zoek de resultaten voor overeenkomende item (s))


    Omdat deze itereert over mappen (in de meeste gevallen), zijn ze inefficiënt voor ons probleem (er zijn uitzonderingen, zoals niet-wildcard globbing - zoals @ShadowRanger opmerkt), dus ik ga er niet op aandringen. Om nog maar te zwijgen over het feit dat in sommige gevallen bestandsnaamverwerking vereist kan zijn.

  4. [Python]: os.toegang(path, mode, *, dir_fd = Geen, effective_ids = False, follow_symlinks = True) wiens gedrag dichtbij is os.path.exists (eigenlijk is het breder, voornamelijk vanwege de 2nd argument)

    • gebruikersrechten kan het bestand "visibility" beperken zoals het document aangeeft:

      ... test of de aanroepende gebruiker de opgegeven toegang heeft pad. mode zou moeten zijn F_OK om het bestaan ​​van een pad te testen ...

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

    Omdat ik ook werk in C, Ik gebruik deze methode ook omdat het onder de motorkap roept inheems APIs (opnieuw, via "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), maar het opent ook een poort voor mogelijk gebruikersfouten, en het is niet zo Pythonic als andere varianten. Dus, zoals @AaronHall terecht opmerkt, gebruik het niet tenzij je weet wat je doet:

    Notitie: native bellen APIs is ook mogelijk via [Python]: ctypes - Een bibliotheek met buitenlandse functies voor Python, maar in de meeste gevallen is het ingewikkelder.

    (Winnen specifiek): sinds msvcr *(vcruntime *) exporteert a [MSDN]: _access, _waccess ook een functiefamilie, hier is een voorbeeld:

    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
    

    Notes:

    • Hoewel het geen goede gewoonte is, gebruik ik het os.F_OK in de call, maar dat is alleen voor de duidelijkheid (de waarde is 0)
    • ik gebruik _waccess zodat dezelfde code werkt python3 en python2 (ondanks unicode gerelateerde verschillen tussen hen)
    • Hoewel dit zich op een heel specifiek gebied richt, het werd niet genoemd in een van de vorige antwoorden


    De Lnx (Ubtu (16 x64)) tegenhanger ook:

    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
    

    Notes:

    • In plaats daarvan hardcoding libcpad ("/lib/x86_64-linux-gnu/libc.so.6") die mogelijk (en waarschijnlijk) zal variëren tussen systemen, None (of de lege tekenreeks) kan worden doorgegeven aan CDLL constructor (ctypes.CDLL(None).access(b"/tmp", os.F_OK)). Volgens [man]: DLOPEN (3):

      Als bestandsnaam is NULL, dan is de geretourneerde handle voor de main   programma. Wanneer gegeven aan dlsym(), deze hendel veroorzaakt een zoekopdracht naar een   symbool in het hoofdprogramma, gevolgd door alle gedeelde objecten geladen op   programma opstarten, en vervolgens alle gedeelde objecten geladen door dlopen() met   de vlag RTLD_GLOBAL.

      • Hoofdprogramma (huidig) (Python) is gekoppeld aan libc, dus de symbolen (inclusief access) wordt geladen
      • Dit moet met zorg worden behandeld, aangezien functies zoals main, Py_Main en (alle) anderen zijn beschikbaar; hen bellen kan rampzalige gevolgen hebben (voor het huidige programma)
      • Dit geldt ook niet voor Winnen (maar dat is niet zo erg, sindsdien msvcrt.dllligt in "% SystemRoot% \ System32" welke is in %PAD% standaard). Ik wilde de dingen verder nemen en dit gedrag repliceren Winnen (en dien een patch in), maar het blijkt dat [MSDN]: GetProcAddress-functie alleen "ziet" geëxporteerd symbolen, dus tenzij iemand de functies in het hoofdprogramma als verklaart __declspec(dllexport) (waarom op aarde de regelmatig persoon zou dat doen?), het hoofdprogramma is laadbaar maar vrijwel onbruikbaar
  5. Installeer wat 3rd Partymodule met bestandssysteemmogelijkheden

    Hoogstwaarschijnlijk zal het vertrouwen op een van de bovenstaande manieren (misschien met kleine aanpassingen).
    Een voorbeeld zou zijn (opnieuw, Winnen specifiek) [GitHub]: Python voor Windows (pywin32) Extensies, wat een is Python omwikkelen WINAPIs.

    Maar omdat dit meer als een tijdelijke oplossing is, stop ik hier.

  6. Een andere (lame) oplossing (gainarie) is (zoals ik het graag noem) het sysadmin aanpak: gebruik Python als een wrapper om shell-opdrachten uit te voeren

    • Winnen:

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

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

Bottom line:

  • Do gebruik try / except / else / finally blokken, omdat ze kunnen voorkomen dat je een reeks vervelende problemen tegenkomt. Een tegenvoorbeeld dat ik kan bedenken, is performance: dergelijke blokken zijn duur, dus probeer ze niet in code te plaatsen die honderdduizenden keer per seconde moet worden uitgevoerd (maar omdat (in de meeste gevallen) schijftoegang is vereist, het zal niet het geval zijn).

Laatste noot (s):

  • Ik zal proberen het up-to-date te houden, suggesties zijn welkom, ik zal alles wat nuttig is, opnemen in het antwoord

136
2018-06-20 19:28



Python 3.4+ heeft een objectgeoriënteerde padmodule: pathlib. Met behulp van deze nieuwe module kunt u controleren of een bestand op deze manier bestaat:

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

Je kunt (en moet meestal) nog steeds een try/except blokkeren bij het openen van bestanden:

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

De pathlib-module bevat veel leuke dingen: handige globbing, controle van de eigenaar van het bestand, gemakkelijker pad-joining, enz. Het is de moeite waard om te controleren. Als je een oudere Python gebruikt (versie 2.6 of later), kun je nog steeds pathlib met pip installeren:

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

Importeer het dan als volgt:

# Older Python versions
import pathlib2 as pathlib

121
2018-02-08 02:38



Geef de voorkeur aan de try-instructie. Het wordt beschouwd als een betere stijl en vermijdt raceomstandigheden.

Neem mijn woord niet op. Er is veel steun voor deze theorie. Hier is een paar:


111
2017-11-04 00:48



Hoe controleer ik of een bestand bestaat, met behulp van Python, zonder een try-opdracht te gebruiken?

Nu beschikbaar sinds Python 3.4, import en instantiate a Path object met de bestandsnaam en vink het selectievakje aan is_file methode (merk op dat dit True retourneert voor symlinks die ook verwijzen naar reguliere bestanden):

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

Als je met Python 2 werkt, kun je de pathlib-module backupport van pypi, pathlib2, of anderszins controleren isfile van de os.path module:

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

Het bovenstaande is waarschijnlijk het beste praktische antwoord hier, maar er is de mogelijkheid van een race-conditie (afhankelijk van wat je probeert te bereiken) en het feit dat de onderliggende implementatie een try, maar Python gebruikt try overal in de uitvoering.

Omdat Python gebruikt try overal is er echt geen reden om een ​​implementatie die deze gebruikt te vermijden.

Maar de rest van dit antwoord probeert deze voorbehouden te overwegen.

Langere, veel meer pedante antwoorden

Beschikbaar sinds Python 3.4, gebruik de nieuwe Path object in pathlib. Let daar op .exists is niet helemaal goed, omdat directories geen bestanden zijn (behalve in de Unix-betekenis dat alles is een bestand).

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

Dus we moeten gebruiken is_file:

>>> root.is_file()
False

Hier is de hulp aan is_file:

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

Dus laten we een bestand nemen waarvan we weten dat het een bestand is:

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

Standaard, NamedTemporaryFile verwijdert het bestand als het gesloten is (en wordt automatisch gesloten als er geen verwijzingen meer zijn).

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

Als je graaft de implementatieMaar dat zie je wel is_file toepassingen 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

Raceomstandigheden: waarom we graag proberen

Wij houden van try omdat het raceomstandigheden vermijdt. Met try, je probeert gewoon je bestand te lezen, verwacht dat het er is, en zo niet, dan krijg je de uitzondering en voer je uit wat fallback-gedrag logisch is.

Als je wilt controleren of een bestand bestaat voordat je het probeert te lezen, en je het misschien verwijdert, dan gebruik je mogelijk meerdere threads of processen, of een ander programma weet dat bestand en kan het verwijderen - je riskeert de kans op een race conditie als je het aanvinkt bestaat, omdat je dan bent racing om het vóór zijn te openen staat (zijn bestaan) verandert.

Raceomstandigheden zijn erg moeilijk te debuggen omdat er een heel klein venster is waarin ze ervoor kunnen zorgen dat je programma faalt.

Maar als dit je motivatie is, jij kan haal de waarde van a try verklaring met behulp van de suppress context manager.

Vermijd raceomstandigheden zonder een try-statement: suppress

Python 3.4 geeft ons de suppress context manager (voorheen de ignore context manager), die semantisch exact hetzelfde doet in minder regels, terwijl ook (op zijn minst oppervlakkig) de oorspronkelijke vraag beantwoordt om een try uitspraak:

from contextlib import suppress
from pathlib import Path

Gebruik:

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

Voor eerdere Pythons zou je je eigen kunnen rollen suppress, maar zonder een try zal meer uitgebreid zijn dan met. ik geloof wel dit is eigenlijk het enige antwoord dat niet wordt gebruikt try op elk niveau in de Python die voorafgaand aan Python 3.4 kan worden toegepast omdat het in plaats daarvan een contextbeheerder gebruikt:

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)

Misschien makkelijker met een poging:

from contextlib import contextmanager

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

Andere opties die niet voldoen aan de vraag "zonder te proberen":

isfile

import os
os.path.isfile(path)

van de docs:

os.path.isfile(path)

Geef Waar terug als pad een bestaand regulier bestand is. Dit volgt symbolisch   links, dus beide islink() en isfile() kan waar zijn voor hetzelfde pad.

Maar als je de bronvan deze functie, zult u zien dat het daadwerkelijk een try-statement gebruikt:

# 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

Het enige wat het doet is het gegeven pad gebruiken om te zien of het statistieken kan krijgen, vangen OSError en dan controleren of het een bestand is als het de uitzondering niet heeft verhoogd.

Als u van plan bent iets met het bestand te doen, zou ik willen voorstellen het meteen te proberen, behalve om een ​​raceconditie te vermijden:

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

os.access

Beschikbaar voor Unix en Windows is os.access, maar om te gebruiken moet je vlaggen doorgeven, en het maakt geen onderscheid tussen bestanden en mappen. Dit wordt meer gebruikt om te testen of de echte aanroepende gebruiker toegang heeft in een verhoogde privilege-omgeving:

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

Het lijdt ook aan dezelfde problemen met de raceomstandigheden als isfile. Van de docs:

Notitie:   Toegang () gebruiken om te controleren of een gebruiker gemachtigd is om b. Een bestand openen   voordat je dit daadwerkelijk doet met open (), creëer je een beveiligingslek, omdat   de gebruiker kan misbruik maken van het korte tijdsinterval tussen controleren en   openen van het bestand om het te manipuleren. Het verdient de voorkeur om EAFP te gebruiken   technieken. Bijvoorbeeld:

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

is beter geschreven als:

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

Vermijd te gebruiken os.access. Het is een functie op laag niveau met meer mogelijkheden voor gebruikersfouten dan de hoger besproken objecten en functies.

Kritiek op een ander antwoord:

Een ander antwoord zegt hierover os.access:

Persoonlijk heb ik deze voorkeur omdat onder de motorkap native API's worden aangeroepen (via "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), maar het opent ook een poort voor mogelijke gebruikersfouten, en het is niet zo Pythonic als andere varianten :

Dit antwoord zegt dat het de voorkeur geeft aan een niet-Pythische, foutgevoelige methode, zonder enige rechtvaardiging. Het lijkt gebruikers aan te moedigen API's op laag niveau te gebruiken zonder ze te begrijpen.

Het creëert ook een contextmanager die, door onvoorwaardelijk terug te keren True, staat alle uitzonderingen toe (inclusief KeyboardInterrupt en SystemExit!) om stil te passeren, wat een goede manier is om bugs te verbergen.

Dit lijkt gebruikers aan te moedigen om slechte praktijken toe te passen.


101
2017-08-11 03:54