Kako provjeriti postoji li datoteka bez iznimaka?

Kako mogu saznati postoji li datoteka ili ne bez korištenja try ?

4683
17 сент. spence91 postavljen na 17 sep . 2008-09-17 15:55 '08 u 15:55 2008-09-17 15:55
@ 47 odgovora
  • 1
  • 2

Ako je razlog zbog kojeg testirate to što možete učiniti nešto kao if file_exists: open_it() , sigurnije je try pokušati otvoriti. Provjera i naknadno otvaranje mogu dovesti do brisanja ili pomicanja datoteke, kao i do onoga što provjeravate i kada je pokušavate otvoriti.

Ako ne namjeravate odmah otvoriti datoteku, možete koristiti os.path.isfile

Return True ako je staza postojeća obična datoteka. To slijedi simboličke veze, tako da i islink () i isfile () mogu biti istinite za isti put.

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

ako trebate biti sigurni da je to datoteka.

Počevši od Pythona 3.4, pathlib modul nudi objektno orijentirani pristup ( pathlib2 u pathlib2 u Pythonu 2.7):

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

Da biste provjerili direktorij, pokrenite:

 if my_file.is_dir(): # directory exists 

Da biste provjerili postoji li objekt Path , bez obzira je li riječ o datoteci ili direktoriju, upotreba exists() :

 if my_file.exists(): # path exists 

Također možete upotrijebiti resolve(strict=True) u try bloku:

 try: my_abs_path = my_file.resolve(strict=True) except FileNotFoundError: # doesn't exist else: # exists 
4266
17 сент. odgovor dano rslite 17 sep . 2008-09-17 15:57 '08 u 15:57 2008-09-17 15:57

Imate funkciju os.path.exists :

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

Ovo vraća istinu za datoteke i direktorije, ali umjesto toga možete koristiti

border=0
 os.path.isfile(file_path) 

za provjeru je li to datoteka. Slijedi simboličke veze.

1820
17 сент. Odgovor daje PierreBdR 17. rujna . 2008-09-17 15:57 '08 u 15:57 2008-09-17 15:57

Za razliku od isfile() , exists() vraća True za direktorije.
Stoga, ovisno o tome želite li koristiti samo obične datoteke ili direktorije, koristite isfile() ili exists() . Ovdje je jednostavan REPL izlaz.

 >>> 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 
858
17 сент. Odgovor daje bortzmeyer na 17 sep . 2008-09-17 18:01 '08 u 18:01 2008-09-17 18:01
 import os.path if os.path.isfile(filepath): 
517
17 сент. odgovor je dat Paulu 17. rujna. 2008-09-17 15:55 '08 u 15:55 2008-09-17 15:55

Koristite os.path.isfile() s 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" 
263
16 янв. Odgovor je dan Yugal Jindle 16. siječnja 2012-01-16 08:57 '12 u 8:57 2012-01-16 08: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 
233
17 сент. Odgovor je dat dobro 17. rujna. 2008-09-17 15:56 '08 u 15:56 2008-09-17 15:56

Iako su gotovo svi mogući putevi navedeni u (barem jednom) postojećih odgovora (na primjer, dodan je specifičan materijal za Python 3.4), pokušat ću sve grupirati.

Napomena : Svaki isječak koda standardne Python knjižnice koji ću objaviti odnosi se na verziju 3.5.3 .

Izjava o problemu :

  1. Provjerite dostupnost datoteka (kontroverzno: također mapu ("posebnu" datoteku)?)
  2. Nemojte koristiti try / exception / else / finally blokove

Moguća rješenja :

  1. [Python 3]: os.path. Postoji (putanja) (također provjerite ostale članove obitelji funkcija, kao što su os.path.isfile , os.path.isdir , os.path.lexists za malo drugačije ponašanje)

    os.stat () za traženu datoteku, čak i ako put fizički postoji. 

    Sve je u redu, ali ako slijedite stablo uvoza:

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

      • genericpath.py, red ~ # 20+

        [Python 3]: os.  stat (put, *, dir_fd = ne, follow_symlinks = True) .  Dakle, isprobajte svoj kod / s izuzetkom slobodnog, ali ispod u skupu okvira (barem) jedan takav blok.  To vrijedi i za druge funkcije ( uključujući os.path.isfile ). 

        1.1. [Python 3]: putanja. is_file ()

        • Ovo je elegantniji (i pitonijski) način rukovanja stazama, ali
        • Pod haubom radi istu stvar (pathlib.py, red ~ # 1330):

        • Koristite [Python 3]: contextlib. potiskivanje (* iznimke) - koje je posebno dizajnirano za selektivno suzbijanje iznimaka


        Ali čini se da su oni omotači probnog / isključenog / else / finally bloka, kao [Python 3]: Sa izjavom s :

        To vam omogućuje da kapsulirate uobičajene pokušaje ... osim ... konačno, koristite obrasce za praktičnu ponovnu upotrebu.

      • Funkcije obilaska datotečnog sustava (i pretraživanje rezultata pomoću odgovarajućih elemenata)


        Budući da pregledavaju mape (u većini slučajeva), one su neučinkovite za naš problem (postoje iznimke, kao što je globalizacija bez zamjenskih znakova - kako naglašava @ShadowRanger), tako da neću inzistirati na njima. Da ne spominjem činjenicu da u nekim slučajevima trebate nositi naziv datoteke.

      • [Python 3]: os. pristup (putanja, način rada, *, dir_fd = none, effective_ids = false, follow_symlinks = TRUE) , čije je ponašanje blizu os.path.exists (zapravo je šire, uglavnom zbog 2. argumenta)

        • Korisničke dozvole mogu ograničiti "vidljivost" datoteke, kako je navedeno u dokumentu:

          ... provjerite ima li korisnik pozivanja određeni pristup stazi. način mora biti F_OK za provjeru postojanja putanje ...

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

        Budući da i ja radim u C-u, koristim i ovu metodu, jer unutar nje naziva vlastite API-je (opet kroz "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), ali i otvara vrata za moguće korisničke pogreške , a to nije kao Pythonic kao druge opcije. Dakle, kao što je @AaronHall ispravno primijetio, nemojte ga koristiti ako ne znate što radite:

        Napomena : pozivanje izvornih API-ja je također moguće putem [Python 3]: ctypes je biblioteka funkcija treće strane za Python , ali u većini slučajeva je složenija.

        (Ovisi o pobjedi ): od vcruntime * (msvcr *) .Dll također izvozi [MS.Docs]: _access, _waccess obitelj funkcija, evo primjera:

         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 

        Napomene :

        • Umjesto hard-kodiranja libc staze ("/lib/x86_64-linux-gnu/libc.so.6"), koja se može (i najvjerojatnije će se razlikovati) u različitim sustavima, None (ili prazan niz) može se proslijediti konstruktoru ctypes.CDLL(None).access(b"/tmp", os.F_OK) ( ctypes.CDLL(None).access(b"/tmp", os.F_OK) ). Prema [man7]: DLOPEN (3) :

          Ako je naziv datoteke NULL, tada je vracena rucka za glavni program. Kada je specificiran dlsym (), ovaj deskriptor uzrokuje traženje znaka u glavnom programu, nakon čega slijede svi uobičajeni objekti koji se učitavaju kada se program pokrene, a zatim svi uobičajeni objekti učitani od strane dlopen () s zastavom RTLD_GLOBAL .

          • Glavni (trenutni) program (python) povezan je s libcom, tako da će njegovi znakovi (uključujući pristup) biti učitani
          • To treba postupati oprezno, budući da su dostupne funkcije kao što su Main, Py_Main i (sve ostale); njihov poziv može biti katastrofalan (za trenutni program)
          • Ovo se također ne odnosi na Win (ali to nije veliki problem, jer je msvcrt.dll u "% SystemRoot% System32", koji je po defaultu u% PATH%). Htjela sam ponoviti ovo ponašanje u Win (i poslati zakrpu), ali, kako se ispostavilo, [MS.Docs]: funkcija GetProcAddress "vidi" samo izvezene znakove, tako da osim ako netko ne proglasi funkciju u glavnoj izvršnoj datoteci kao __declspec(dllexport) (zašto bi to običan čovjek učinio na Zemlji?), glavni program se može preuzeti, ali uglavnom neprikladan za upotrebu
      • Instalirajte neki modul treće strane s mogućnostima datotečnog sustava

        Najvjerojatnije će se oslanjati na jednu od gore navedenih metoda (možda s malim postavkama).
        Jedan primjer bi bio (opet, Win-specific) [GitHub]: mhammond / pywin32 - Python proširenja za Windows (pywin32) , koji su Python omot za WINAPI.

        No, budući da je ovo više nalik na zaobilazno rješenje, ovdje ću stati.

      • Drugo (slabo) zaobilazno rješenje (gainarie) je (kako ga ja zovem) sysadmin pristup: upotreba Pythona kao ljuske za izvršavanje naredbi ljuske

        • osvojiti:

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

Ishod :

  • Pokušajte / s izuzetkom / inače / na kraju blokirajte, jer vas mogu spriječiti u lansiranju u niz neugodnih problema. Kontra-primjer koji mogu zamisliti je produktivnost: takvi blokovi su skupi, stoga pokušajte da ih ne stavljate u kod, koji mora raditi stotine tisuća puta u sekundi (već zato što (u većini slučajeva) uključuje pristup disku, neće biti tako).

Završne napomene :

  • Pokušat ću ga ažurirati, bilo kakvi prijedlozi su dobrodošli, uključit ću sve što je korisno kao odgovor
166
20 июня '17 в 22:28 2017-06-20 22:28 odgovor je dao CristiFati 20. lipnja 2006. u 10:28 2017-06-20 22:28

To je najlakši način da provjerite postoji li datoteka. Samo zato što je datoteka postojala kada ste provjerili ne jamči da će ona biti tamo kada je trebate otvoriti.

 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") 
143
27 июня '13 в 16:38 2013-06-27 16:38 odgovor je dan un33k 27. lipnja '13 u 16:38 2013-06-27 16:38

Python 3.4+ ima objektno orijentirani put: pathlib . Koristeći ovaj novi modul, možete provjeriti postoji li datoteka na sljedeći način:

 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 

Možete (i obično trebate) koristiti blok za try/except pri otvaranju datoteka:

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

Postoji mnogo cool stvari u pathlib modulu: prikladno glađenje, provjera vlasnika datoteke, pojednostavljenje veze itd. Vrijedi provjeriti. Ako koristite stariji Python (verzija 2.6 ili noviji), još uvijek možete instalirati pathlib s pipom:

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

Zatim ga uvezite kako slijedi:

 # Older Python versions import pathlib2 as pathlib 
127
08 февр. odgovor Cody Piersall 08. veljače. 2014-02-08 05:38 '14 u 5:38 2014-02-08 05:38

Prednost operateru za pokušaj. Smatra se najboljim stilom i izbjegava uvjete utrke.

Ne uzimaj moju riječ za to. Postoji velika podrška ovoj teoriji. Evo par:

113
04 нояб. odgovor je dat pkoch 04 Nov. 2009-11-04 03:48 '09 u 3:48 2009-11-04 03:48

Kako provjeriti postoji li datoteka koristeći Python bez upotrebe pokušaja?

Sada, počevši od Pythona 3.4, uvezite i stvorite instancu objekta Path s nazivom datoteke i provjerite metodu is_file (imajte na umu da se time vraća True za simbolične veze koje upućuju na obične datoteke):

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

Ako ste na Pythonu 2, možete izraditi sigurnosnu kopiju pathlib modula iz pathlib2 ili inače provjeriti isfile na os.path modulu:

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

Navedeno je vjerojatno najbolji pragmatični izravni odgovor ovdje, ali postoji mogućnost uvjeta utrke (ovisno o tome što pokušavate postići) i činjenicu da implementacija baze koristi try , ali Python koristi svugdje u svojoj implementaciji.

Budući da Python koristi svugdje, nema razloga izbjegavati implementaciju koja ga koristi.

Ali ostatak ovog odgovora pokušava razmotriti te rezerve.

Dulji, mnogo pedantniji odgovor

Dostupan iz Pythona 3.4, koristite novi objekt Path u pathlib . Imajte na umu da .exists nije sasvim u redu, jer direktorije nisu datoteke (osim za unix, to je sve datoteka).

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

Dakle, moramo koristiti is_file :

 >>> root.is_file() False 

Ovdje je pomoć na is_file :

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

Neka datoteka koju znamo bude datoteka:

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

Prema zadanim postavkama, NamedTemporaryFile briše datoteku kada je zatvorena (i automatski se zatvara kada nema veza).

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

Ako iskopate implementaciju , vidjet ćete da is_file koristi 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 

Uvjeti utrke: zašto volimo pokušati

Volimo try , jer izbjegava uvjete utrke. Koristeći try jednostavno pokušajte pročitati datoteku, očekujući da bude tamo, a ako ne, uhvatit ćete iznimku i izvesti sve moguće akcije sigurnosnog kopiranja.

Ako želite provjeriti postoji li datoteka prije pokušaja čitanja, a možete je izbrisati, a zatim možete upotrijebiti nekoliko niti ili procesa, ili neki drugi program zna za tu datoteku i možete je izbrisati - riskirate stanje utrke ako provjerite njega, jer se onda požurite otvoriti ga prije nego se njegova država (njegovo postojanje) promijeni.

Uvjetima utrke vrlo je teško otkloniti greške, jer postoji vrlo mali prozor u kojem mogu srušiti vaš program.

Ali ako je to vaša motivacija, možete dobiti vrijednost instrukcije try pomoću suppress kontekstnog upravitelja.

Izbjegavajte utrke bez pokušaja: suppress upute

Python 3.4 daje nam suppress kontekstnog upravitelja (koji je prethodno ignore upravitelja konteksta), koji semantički točno radi istu stvar u manje redaka, a također (barem površno), zadovoljavajući izvorni upit, kako bi se izbjegla instrukcija try :

 from contextlib import suppress from pathlib import Path 

Upotreba:

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

Za ranije Pythone, možete invertirati vlastiti suppress , ali bez try bit će detaljniji nego s. Iskreno vjerujem da je to zapravo jedini odgovor koji ne koristi try na bilo kojoj razini u Pythonu , koji se može primijeniti prije Pythona 3.4, jer umjesto toga koristi upravitelja konteksta:

 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) 

Možda je lakše isprobati:

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

Ostale opcije koje ne odgovaraju upitu "bez pokušaja":

ISFILE

 import os os.path.isfile(path) 

iz dokumenata :

os.path.isfile(path)

Vraća True ako je staza postojeća obična datoteka. To slijedi simboličku vezu, tako da i islink() i isfile() parametri mogu biti istiniti za isti put.

Ali ako ispitate izvor ove funkcije, vidjet ćete da zapravo koristi naredbu 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 

Sve što radi jest koristiti određenu stazu kako bi saznao može li dobiti statističke podatke o njemu tako što će uhvatiti OSError a zatim provjeriti je li datoteka ako nije OSError izuzetak.

Ako namjeravate učiniti nešto s datotekom, predlažem da je pokušate s probnim iznimkom kako biste izbjegli uvjet utrke:

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

os.access

Dostupno za Unix i Windows os.access , ali za korištenje morate proći zastavice i ne razlikovati datoteke i direktorije. Ovo se više koristi za provjeru ima li stvarni pozivatelj pristup u okruženju s povišenim ovlastima:

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

On također pati od istih problema s uvjetima utrke kao isfile . Iz dokumenata :

Napomena: Koristite access () da biste provjerili je li korisnik, primjerice, dopušten. открыть файл перед тем как это сделать, используя open(), создает дыру в безопасности, потому что пользователь может использовать короткий промежуток времени между проверкой и открыв файл, чтобы манипулировать им. Его предпочтительнее использовать EAFP методы. Na primjer:

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