Kaip patikrinti, ar failas egzistuoja be išimčių?

Kaip sužinoti, ar failas yra ar ne, naudodami try ?

4683
17 сент. spence91 nustatytas 17 sep . 2008-09-17 15:55 '08 at 15:55 2008-09-17 15:55
@ 47 atsakymai
  • 1
  • 2

Jei priežastis, kodėl bandote, yra todėl, kad galite padaryti kažką panašaus, if file_exists: open_it() , saugiau naudoti try atidaryti. Tikrinimas ir vėlesnis atidarymas gali sukelti failo ištrynimą arba judėjimą, taip pat tai, ką tikrinate ir kada bandote jį atidaryti.

Jei neplanuojate atidaryti failo iš karto, galite naudoti os.path.isfile

Grįžti True jei kelias yra esamas reguliarus failas. Tai atitinka simbolines nuorodas, todėl ir islink (), ir isfile () gali būti teisingi tam pačiam keliui.

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

jei reikia įsitikinti, kad tai failas.

Pradedant nuo 3.4 „Python“, „ pathlib modulis siūlo į objektą orientuotą metodą ( pathlib2 pathlib2 „Python 2.7“):

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

Norėdami patikrinti katalogą, paleiskite:

 if my_file.is_dir(): # directory exists 

Jei norite patikrinti, ar Path objektas yra, neatsižvelgiant į tai, ar jis yra failas, ar katalogas, naudokite exists() :

 if my_file.exists(): # path exists 

Taip pat galite naudoti resolve(strict=True) try bloke:

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

Turite funkciją os.path.exists :

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

Tai grąžinama tiek failų, tiek katalogų atveju, tačiau galite naudoti

border=0
 os.path.isfile(file_path) 

patikrinti, ar tai failas. Tai atitinka simbolinius ryšius.

1820 m
17 сент. Atsakymą pateikė PierreBdR apie 17 sep . 2008-09-17 15:57 '08 15:57 2008-09-17 15:57

Skirtingai nuo isfile() , exists() bus True katalogams.
Todėl, priklausomai nuo to, ar norite naudoti tik įprastus failus ar katalogus, naudosite „ isfile() arba exists() . Čia yra paprastas REPL išėjimas.

 >>> 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 сент. Atsakymą pateikė bortzmeyer 17 sep . 2008-09-17 18:01 '08, 6:01 pm, 2008-09-17 18:01
 import os.path if os.path.isfile(filepath): 
517
17 сент. atsakymas duotas Pauliaus 17 sep. 2008-09-17 15:55 '08 at 15:55 2008-09-17 15:55

Naudokite os.path.isfile() su 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 янв. Atsakymas pateikiamas Yugal Jindle sausio 16 d 2012-01-16 08:57 '12 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 сент. Atsakymas duotas naudos gavėjui 17 rugsėjis 2008-09-17 15:56 '08, 15:56, 2008-09-17 15:56

Nors beveik visi galimi keliai buvo išvardyti (bent vienas iš) esamų atsakymų (pavyzdžiui, pridėta specifinė medžiaga „Python 3.4“), bandysiu suskirstyti viską kartu.

Pastaba : kiekvienas standartinio „Python“ bibliotekos kodo fragmentas, kurį skelbsiu, susijęs su 3.5.3 versija.

Problema :

  1. Patikrinkite failo prieinamumą (prieštaringas: taip pat aplankas („specialus“ failas)?)
  2. Nenaudokite bandymo / išimties / kitaip / galiausiai blokų

Galimi sprendimai :

  1. [Python 3]: os.path. Yra (kelias) (taip pat patikrinkite kitus funkcijų šeimos narius, pvz., os.path.isfile , os.path.isdir , os.path.lexists , šiek tiek kitokiam elgesiui)

    os.stat () prašomam failui, net jei kelias fiziškai egzistuoja. 

    Viskas gerai, bet jei sekate importo medį:

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

      • genericpath.py, eilutė ~ # 20+

      • Failų sistemos judėjimo funkcijos (ir rezultatų paieška pagal suderintus elementus)


        Kadangi jie žiūri per aplankus (daugeliu atvejų) yra neveiksmingi mūsų problemai (yra išimčių, pvz., Globalizacija be pakaitos ženklų, kaip nurodė @ShadowRanger), todėl aš jiems neužsimerksiu. Jau nekalbant apie tai, kad kai kuriais atvejais gali tekti tvarkyti failo pavadinimą.

      • [Python 3]: os. prieiga (kelias, režimas, *, dir_fd = nėra, efektyvus_pasaulis = false, follow_symlinks = TRUE) , kurių elgesys yra artimas os.path.exists (iš tikrųjų jis yra platesnis, daugiausia dėl 2 argumento)

        • Naudotojo teisės gali apriboti failo „matomumą“, kaip nurodyta dokumente:

          ... patikrinkite, ar skambinantysis vartotojas turi nurodytą kelio prieigą. režimas turi būti F_OK, kad patikrintumėte, ar yra kelias ...

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

        Kadangi aš taip pat dirbau C, taip pat naudoju šį metodą, nes jo viduje jis vadina savo API (dar kartą per „$ {PYTHON_SRC_DIR} /Modules/posixmodule.c“), tačiau taip pat atveria vartus galimų naudotojo klaidų atveju , ir tai nėra toks pat Pythonic kaip ir kitos galimybės. Taigi, kaip @AaronHall teisingai pažymėjo, nenaudokite, nebent žinote, ką darote:

        Pastaba : skambinti vietinėms API taip pat galima per [Python 3]: ctypes yra trečiųjų šalių funkcijų biblioteka Python , tačiau daugeliu atvejų ji yra sudėtingesnė.

        (Priklauso nuo laimėjimo ): nuo vcruntime * (msvcr *) Dll taip pat eksportuoja [MS.Docs]: _access, _waccess funkcijų šeimą, čia yra pavyzdys:

         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 

        Pastabos :

        • Vietoj kietojo kodavimo libc kelio ("/lib/x86_64-linux-gnu/libc.so.6"), kuris gali (ir greičiausiai bus) skirtis įvairiose sistemose, Nėra (arba tuščia eilutė) gali būti perduodama ctypes.CDLL(None).access(b"/tmp", os.F_OK) konstruktoriui ctypes.CDLL(None).access(b"/tmp", os.F_OK) ( ctypes.CDLL(None).access(b"/tmp", os.F_OK) ). Pagal [man7]: DLOPEN (3) :

          Jei failo pavadinimas yra NULL, tada grąžinama rankena skirta pagrindinei programai. Nurodant dlsym (), šis deskriptorius pagrindinėje programoje suranda požymį, po kurio seka visi įprasti objektai, kurie įkeliami, kai programa paleidžiama , ir tada visi įprasti objektai, kuriuos dlopen () įkėlė su RTLD_GLOBAL vėliava.

          • Pagrindinė (dabartinė) programa (python) yra susieta su libc, todėl jos simboliai (įskaitant prieigą) bus įkelti
          • Tai turėtų būti tvarkoma atsargiai, nes tokios funkcijos kaip pagrindiniai, Py_Main ir (visi kiti) yra prieinami; jų kvietimas gali būti pražūtingas (dabartinei programai)
          • Tai taip pat netaikoma „Win“ (bet tai nėra tokia didelė problema, nes msvcrt.dll yra „% SystemRoot% System32“, kuri pagal nutylėjimą yra% PATH%). Norėjau eiti į priekį ir pakartoti šį elgesį „Win“ (ir atsiųskite pleistrą), bet, kaip paaiškėjo, [MS.Docs]: „GetProcAddress“ funkcija „mato“ eksportuoja tik simbolius, todėl, jei kas nors neįtvirtina pagrindinės vykdomojo failo kaip __declspec(dllexport) (kodėl paprastas žmogus tai padarys Žemėje?), pagrindinė programa yra parsisiunčiama, bet dažniausiai netinkama naudoti
      • Įdiekite trečiųjų šalių modulį su failų sistemos galimybėmis

        Labiausiai tikėtina, kad jis remsis vienu iš pirmiau minėtų metodų (galbūt su mažais nustatymais).
        Vienas iš pavyzdžių galėtų būti (vėl, konkretus Win) [GitHub]: mhammond / pywin32 - „Python“ plėtiniai „Windows“ (pywin32) , kurie yra „Python“ pakuotė „WINAPI“.

        Tačiau, kadangi tai labiau panašu į problemą, čia sustosiu.

      • Kitas (silpnas) problemos sprendimas (gainarie) yra (kaip aš jį vadinu) sysadmin metodas: naudojant „Python“ kaip apvalkalą korpuso komandų vykdymui

        • Laimėti:

           [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 

Rezultatas :

  • Pabandykite /, išskyrus / kitaip / galutinai blokus, nes jie gali užkirsti kelią jums pradėti nemalonių problemų seriją. Kaip pavyzdį galiu galvoti apie produktyvumą: tokie blokai yra brangūs, todėl stenkitės ne įdėti juos į kodą, kurį jis turi paleisti šimtus tūkstančių kartų per sekundę (bet kadangi (daugeliu atvejų) tai apima diskų prieigą, tai nebus taip).

Galutinė (-ios) pastaba (-os) :

  • Aš stengsiu jį atnaujinti, bet kokie pasiūlymai yra sveikintini, įtrauksiu viską, kas bus naudinga atsakant
166
20 июня '17 в 22:28 2017-06-20 22:28 atsakymą pateikė CristiFati , birželio 20 d. 17, 10:28 2017-06-20 22:28

Tai paprasčiausias būdas patikrinti, ar failas egzistuoja. Tiesiog todėl, kad failas, kai patikrinote , negarantuoja, kad jis bus ten, kai jį reikia atidaryti.

 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 atsakymas duotas un33k birželio 27 d. 13 val. 16:38 2013-06-27 16:38

„Python 3.4+“ turi objektą orientuotą kelią: pathlib . Naudodami šį naują modulį galite patikrinti, ar failas egzistuoja taip:

 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 

Atidarius failus, galite (ir paprastai turėtumėte) naudoti try/except bloką:

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

Kelias modulyje yra daug vėsių dalykų: patogus lyginimas, failo savininko tikrinimas, ryšio supaprastinimas ir kt. Verta patikrinti. Jei naudojate senesnį „Python“ (2.6 arba naujesnė versija), vis tiek galite įdiegti „pathlib“ su pip:

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

Tada importuokite jį taip:

 # Older Python versions import pathlib2 as pathlib 
127
08 февр. atsakymas, kurį pateikė Cody Piersall 2014-02-08 05:38 '14 at 5:38 2014-02-08 05:38

Geriau pabandykite operatorių. Jis laikomas geriausiu stiliumi ir vengia rasės sąlygų.

Nepriimkite mano žodžio. Ši teorija yra daug remiama. Čia yra pora:

113
04 нояб. atsakymas pateikiamas pkoch 04.11 . 2009-11-04 03:48 '09, 3:48 2009-11-04 03:48

Kaip patikrinti, ar failas naudojamas naudojant „Python“, nenaudojant bandymo pareiškimo?

Dabar, pradedant nuo „Python 3.4“, importuokite ir sukurkite Path objekto egzempliorių su failo pavadinimu ir patikrinkite „ is_file metodą (atkreipkite dėmesį, kad tai grąžina „True“ simbolinėms nuorodoms, rodančioms įprastus failus):

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

Jei esate „Python 2“, galite kopijuoti pathlib modulį iš „ pathlib2 , „ pathlib2 arba dar patikrinti „ isfile “ „ os.path modulyje:

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

Pirmiausia tai yra geriausias pragmatiškas tiesioginis atsakymas čia, tačiau yra galimybė dalyvauti lenktynėse (priklausomai nuo to, ką bandote atlikti), ir į tai, kad bazės įgyvendinimas naudoja try , tačiau „Python“ naudojasi try visur.

Kadangi „Python“ naudojasi try visur, nėra jokios priežasties vengti jo panaudojimo.

Tačiau likęs atsakymas bando apsvarstyti šias abejones.

Ilgesnis, daug daugiau pedantinis atsakymas

Naudojant Python 3.4, naudokite naują Path objektą. Atkreipkite dėmesį, kad .exists ne visai teisinga, nes katalogai nėra failai (išskyrus „unix“, kad visi yra failas).

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

Taigi, mes turime naudoti is_file :

 >>> root.is_file() False 

Čia yra pagalba, susijusi su is_file :

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

Taigi leiskite failui, kurį žinome, failą:

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

Numatyta, kad „ NamedTemporaryFile ištrina failą, kai jis yra uždarytas (ir automatiškai užsidaro, kai nėra nuorodų į jį).

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

Jei is_file įgyvendinimą , pamatysite, kad „ is_file naudoja:

 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 

Rasės sąlygos: kodėl norime pabandyti

Norime try , nes vengia rasės sąlygų. Naudodami try tiesiog pabandykite perskaityti savo failą, tikėdamiesi, kad jis bus, ir, jei ne, jums bus taikoma išimtis ir atlikti visus galimus atsarginius veiksmus.

Jei norite patikrinti, ar failas egzistuoja prieš bandant jį perskaityti, ir galite jį ištrinti, ir tada galite naudoti keletą sričių arba procesų, arba kita programa žino apie šį failą ir gali jį ištrinti - rizikuojate lenktynių sąlygomis. jį, nes tada jūs skubate jį atidaryti prieš jo valstybės (jo egzistavimo) pasikeitimus.

Rasių sąlygas labai sunku derinti, nes yra labai mažas >

Bet jei tai yra jūsų motyvacija, galite gauti try nurodymo vertę naudodami konteksto valdytojo suppress .

Venkite rasės sąlygų be bandymo: suppress instrukcijas

„Python 3.4“ suteikia mums suppress konteksto valdytojo (anksčiau ignore kontekstą valdantį), kuris semantiškai tiksliai tas pats, mažiau linijų, taip pat (bent jau paviršutiniškai), atitinkantis pradinį užklausą, kad išvengtumėte try instrukcijos:

 from contextlib import suppress from pathlib import Path 

Naudoti:

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

Ankstesniems Pythonams galite apversti savo suppress , bet be try bus išsamesnis nei su. Aš tikrai manau, kad tai iš tikrųjų yra vienintelis atsakymas, kuris nenaudoja try bet kuriame „Python“ lygyje , kurį galima taikyti prieš „Python 3.4“, nes jis naudoja konteksto valdytoją:

 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) 

Gali būti lengviau išbandyti:

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

Kitos parinktys, kurios neatitinka užklausos „nebandyti“:

ISFILE

 import os os.path.isfile(path) 

dokumentų :

os.path.isfile(path)

Grąžina teisingą, jei kelias yra esamas reguliarus failas. Tai atitinka simbolinę nuorodą, taigi ir islink() ir isfile() parametrai gali būti teisingi tam pačiam keliui.

Bet jei ištirsite šios funkcijos šaltinį, pamatysite, kad jis iš tikrųjų naudoja bandymo pareiškimą:

 # 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 

Viskas, ką jis daro, yra naudodamas nurodytą kelią, kad sužinotų, ar jis gali gauti statistiką apie jį, gaudydamas OSError ir tada patikrindamas, ar jis yra failas, jei jis OSError išimties.

Jei ketinate kažką daryti su byla, siūlau tiesiogiai bandyti jį su bandymu, išskyrus atvejus, kai išvengsite lenktynių būklės:

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

os.access

Galima naudoti „Unix“ ir „Windows os.access , tačiau norint naudoti, turite praeiti vėliavomis ir neskirti failų ir katalogų. Tai dažniau naudojama norint patikrinti, ar tikrasis skambinantysis turi prieigą aplinkoje su padidintomis privilegijomis:

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

Jis taip pat kenčia nuo tų pačių problemų kaip ir rasės sąlygomis. Iš dokumentų :

Pastaba: naudokite prieigą (), kad patikrintumėte, ar, pavyzdžiui, naudotojas yra leidžiamas. atidarius failą prieš tai naudojant atvirą (), sukuriama saugumo skylė, nes vartotojas gali naudoti trumpą laiką tarp failo tikrinimo ir atidarymo, kad galėtų manipuliuoti juo. Tai geriau naudoti EAFP metodus. Pavyzdžiui:

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