Pytanie Jak sprawdzić, czy plik istnieje?


Jak sprawdzić, czy plik istnieje, czy nie, bez używania try komunikat?


4361
2017-09-17 12:55


pochodzenie




Odpowiedzi:


Jeśli powodem, dla którego sprawdzasz, możesz zrobić coś takiego if file_exists: open_it(), bezpieczniej jest używać a try wokół próby otwarcia. Sprawdzanie i otwieranie ryzykuje usunięcie lub przeniesienie pliku lub coś pomiędzy sprawdzaniem i próbą otwarcia.

Jeśli nie chcesz od razu otwierać pliku, możesz użyć os.path.isfile

Powrót True jeśli ścieżka jest istniejącym zwykłym plikiem. Podąża za symbolicznymi linkami, więc oba islink () i isfile () może być prawdziwe dla tej samej ścieżki.

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

jeśli musisz mieć pewność, że to plik.

Począwszy od wersji 3.4 Python pathlib moduł oferuje podejście obiektowe (przeniesione do pathlib2 w Pythonie 2.7):

from pathlib import Path

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

Aby sprawdzić katalog, wykonaj następujące czynności:

if my_file.is_dir():
    # directory exists

Aby sprawdzić, czy Path obiekt istnieje niezależnie od tego, czy jest to plik czy katalog, użyj exists():

if my_file.exists():
    # path exists

Możesz także użyć resolve() w try blok:

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

3963
2017-09-17 12:57



dotyczące pierwszej uwagi (użyj "spróbuj", jeśli sprawdzisz przed otwarciem), niestety to nie zadziała, jeśli chcesz otworzyć przed dodaniem, że istnieje, ponieważ tryb "a" zostanie utworzony, jeśli nie istnieje. - makapuf
dostaję os.path.isfile nie istnieje. - JeromeJ


Masz os.path.exists funkcjonować:

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

To się zwraca True zarówno dla plików, jak i katalogów, ale możesz zamiast tego użyć

os.path.isfile(file_name)

przetestować, czy jest to plik specjalnie. Podąża za dowiązaniami symbolicznymi.


1626
2017-09-17 12:57





w odróżnieniu isfile(), exists() wróci True dla katalogów.
Więc w zależności od tego, czy chcesz używać tylko zwykłych plików, czy też katalogów, użyjesz isfile() lub exists(). Oto proste wyjście 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

837
2017-09-17 15:01





import os.path

if os.path.isfile(filepath):

468
2017-09-17 12:55





Posługiwać się os.path.isfile() z 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"

223
2018-01-16 05:57



mając wiele warunków, z których niektóre są zbyteczne, jest mniej jasne i wyraźne. - wim
Jest również zbędny. Jeśli plik nie istnieje, os.access() zwróci false. - user207421
@EJP W plikach linux mogą istnieć, ale nie są dostępne. - e-info128


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



Ta odpowiedź jest błędna. os.path.exists zwraca true dla rzeczy, które nie są plikami, takimi jak katalogi. Daje to fałszywe alarmy. Zobacz inne odpowiedzi, które zalecają os.path.isfile. - Chris Johnson
Katalog jest rodzajem pliku unix.stackexchange.com/questions/197439/... - James Roth


Jest to najprostszy sposób sprawdzenia, czy plik istnieje. Właśnie bo plik istnieje, gdy zaznaczyłeś, nie gwarancja że będzie tam, kiedy będziesz musiał go otworzyć.

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

139
2018-06-27 13:38



Tak długo, jak zamierzasz uzyskać dostęp do pliku, stan wyścigu istnieje, niezależnie od tego, jak zbudowany jest twój program. Twój program nie może zagwarantować, że inny proces na komputerze nie zmodyfikował pliku. To właśnie Eric Lippert określa jako egzogeniczny wyjątek. Nie można tego uniknąć poprzez wcześniejsze sprawdzenie istnienia pliku. - Isaac Supeene
@IsaacSupeene Najlepszą praktyką jest uczynienie okna operacji (pliku) tak małym, jak to możliwe, po którym następuje właściwa obsługa wyjątków - un33k


2017/12/22:

Chociaż prawie każdy możliwy sposób został wymieniony w (przynajmniej jednej z) istniejących odpowiedzi (np. Python 3.4 określone rzeczy zostały dodane), spróbuję pogrupować wszystko razem.

Uwaga: każdy kawałek Pyton standardowy kod biblioteki, który mam zamiar opublikować, należy do wersji 3.5.3 (Cytaty doc są wersją 3 konkretny).

Stwierdzenie problemu:

  1. Sprawdź plik (sporny: także folder ("specjalny" plik)?) istnienie
  2. Nie używaj try / except / else / finally Bloki

Możliwe rozwiązania:

  1. [Python]: os.path.istnieje(ścieżka) (sprawdź także inne funkcje członków rodziny, takie jak os.path.isfile, os.path.isdir, os.path.lexists dla nieco innych zachowań)

    os.path.exists(path)
    

    Powrót True gdyby ścieżka odnosi się do istniejącej ścieżki lub otwartego deskryptora pliku. Zwroty False dla zepsutych dowiązań symbolicznych. Na niektórych platformach ta funkcja może powrócić False jeśli uprawnienie nie zostanie udzielone do wykonania os.stat () na żądanym pliku, nawet jeśli ścieżka fizycznie istnieje.

    Wszystko dobrze, ale jeśli śledzisz drzewo importu:

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

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

    to tylko try/except blokuj wokół [Python]: os.stat(ścieżka, *, dir_fd = Brak, follow_symlinks = True). Twój kod jest try/except wolny, ale niższy w framestack (przynajmniej) jeden taki blok. Dotyczy to również innych funkcji (włącznie z  os.path.isfile).

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

    • To jest hodowca (i więcej pytonic) sposób obsługi ścieżek, ale
    • Pod maską to robi dokładnie to samo (pathlib.py, linia ~ # 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]: With Statement Context Managers. Zarówno:

    • Stworzyć jeden:

      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 ...)
      
      • I jego użycie - będę replikować isfile zachowanie (zauważ, że jest to tylko do celów demonstracyjnych, nie nie spróbuj napisać taki kod dla produkcja):

        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
        
    • Posługiwać się [Python]: contextlib.stłumić(* wyjątki) - który był konkretnie Przeznaczony do selektywnego tłumienia wyjątków


    Ale wydają się być owijkami try/except/else/finally bloki, jako [Python]: The z komunikat stwierdza:

    To pozwala na wspólne próbować...z wyjątkiem...Wreszcie wzorce użycia do hermetyzacji dla wygodnego ponownego użycia.

  3. Funkcje przejścia systemu plików (i wyszukiwanie wyników dla pasujących elementów)


    Ponieważ te iteracje nad folderami (w większości przypadków) są nieskuteczne dla naszego problemu (są wyjątki, na przykład niezgałęzione globbing - jak zauważył @ShadowRanger), więc nie zamierzam ich nalegać. Nie wspominając o tym, że w niektórych przypadkach może być wymagane przetwarzanie pliku.

  4. [Python]: os.dostęp(ścieżka, tryb, *, dir_fd = Brak, effective_ids = False, follow_symlinks = True) którego zachowanie jest bliskie os.path.exists (w rzeczywistości jest szerszy, głównie z powodu 2nd argument)

    • uprawnienia użytkownika może ograniczyć plik "widoczność", ponieważ dokument stwierdza:

      ... sprawdź, czy użytkownik wywołujący ma określony dostęp ścieżka. tryb powinno być F_OK przetestować istnienie ścieżki ...

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

    Od kiedy również pracuję doUżywam tej metody również dlatego, że pod maską dzwoni ojczysty APIs (ponownie, przez "$ {PYTHON_SRC_DIR} /Modules/posixmodule.c"), ale otwiera również bramę dla możliwości błędy użytkownikai to nie jest tak Pytonic jak inne warianty. Tak więc, jak słusznie zauważyła @AaronHall, nie używaj go, chyba że wiesz, co robisz:

    Uwaga: dzwonienie natywnie APIs jest również możliwe przez [Pyton]: ctypes - Obca biblioteka funkcji dla Pythona, ale w większości przypadków jest to bardziej skomplikowane.

    (Zdobyć specyficzne): od msvcr *(vcruntime *) eksportuje a [MSDN]: _access, _waccess również rodzina funkcji, oto przykład:

    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
    

    Uwagi:

    • Chociaż nie jest to dobra praktyka, używam os.F_OK w rozmowie, ale to tylko dla jasności (jego wartość jest 0)
    • używam _waccess aby ten sam kod działał Python3 i Python2 (pomimo unicode powiązane różnice między nimi)
    • Chociaż dotyczy to bardzo specyficznego obszaru, nie wspomniano o tym w żadnej z poprzednich odpowiedzi


    The Lnx (Ubtu (16 x64)) również odpowiednik:

    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
    

    Uwagi:

    • Zamiast twardego kodowania libcścieżka ("/lib/x86_64-linux-gnu/libc.so.6"), które mogą (i najprawdopodobniej będą) różnić się w różnych systemach, None (lub pusty ciąg) można przekazać do CDLL konstruktor (ctypes.CDLL(None).access(b"/tmp", os.F_OK)). Według [mężczyzna]: DLOPEN (3):

      Gdyby Nazwa pliku ma wartość NULL, a następnie zwrócona klamka jest dla głównej   program. Po podaniu dlsym(), ten uchwyt powoduje wyszukiwanie a   symbol w głównym programie, a następnie wszystkie udostępnione obiekty załadowane w   uruchomienie programu, a następnie wszystkie udostępnione obiekty załadowane przez dlopen() z   Flaga RTLD_GLOBAL.

      • Główny (obecny) program (pyton) jest powiązany z libc, więc jego symbole (w tym access) zostanie załadowany
      • Należy to traktować ostrożnie, ponieważ funkcje takie jak main, Py_Main i (wszystkie) inne są dostępne; ich wywoływanie może mieć katastrofalne skutki (w obecnym programie)
      • Nie dotyczy to również Zdobyć (ale to nie jest taka wielka sprawa, ponieważ msvcrt.dllznajduje się w "% SystemRoot% \ System32" która jest w %ŚCIEŻKA% domyślnie). Chciałem zrobić wszystko dalej i powtórzyć to zachowanie Zdobyć (i prześlij łatkę), ale jak się okazuje, [MSDN]: funkcja GetProcAddress tylko "widzi" wyeksportowany symbole, więc chyba że ktoś deklaruje funkcje w głównym pliku wykonywalnym jako __declspec(dllexport) (dlaczego na Ziemi regularny człowiek to zrobił?), program główny jest ładowalny, ale prawie bezużyteczny
  5. Zainstaluj około 3r & D Moduł Party z możliwościami systemu plików

    Najprawdopodobniej będzie polegać na jednym ze sposobów powyżej (może z niewielkimi dostosowaniami).
    Jednym z przykładów byłaby (ponownie Zdobyć konkretny) [GitHub]: Rozszerzenia Python dla Windows (pywin32), który jest Pyton otoki się WINAPIs.

    Ale ponieważ jest to bardziej podobne do obejścia, zatrzymuję się tutaj.

  6. Kolejne (lame) obejście (gainarie) jest (jak lubię to nazywać) sysadmin podejście: użycie Pyton jako wrapper do wykonywania poleceń powłoki

    • Zdobyć:

      (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
      

Dolna linia:

  • Zrobić posługiwać się try / except / else / finally bloków, ponieważ mogą one zapobiec pojawieniu się serii nieprzyjemnych problemów. Kontrapunktem, który mogę wymyślić, jest wydajność: takie bloki są kosztowne, więc staraj się nie umieszczać ich w kodzie, który powinien działać setki tysięcy razy na sekundę (ale ponieważ (w większości przypadków) wymaga dostępu do dysku, tak nie będzie).

Ostateczna uwaga (e):

  • Postaram się go aktualizować, wszelkie sugestie są mile widziane, włączę wszystko, co może się przydać w odpowiedzi

137
2018-06-20 19:28



Czy możesz rozwinąć to stwierdzenie? "Chociaż nie jest to dobrą praktyką, używam w wywołaniu os.F_OK, ale to tylko dla jasności (jego wartość to 0)" - sk8asd123
@ Sk8asd123: Trudno to zrobić w komentarzu: ogólnie rzecz biorąc, najlepiej jest używać stałych z funkcjami, z którymi się łączą. Dotyczy to pracy z wieloma modułami, które definiują tę samą stałą, ponieważ niektóre z nich mogą nie być aktualne i najlepiej jest zsynchronizować funkcje i stałe. Podczas pracy z ctypes (wywołując funkcje bezpośrednio) Powinienem określić stałą (od MSDN) lub w ogóle nie używać stałej. To tylko wskazówka, której używam, w 99,9% prawdopodobnie nie robi różnicy (funkcjonalnie). - CristiFati
@CristiFati: Od 3.6, glob.iglob (i glob.glob również) są oparte na os.scandir, więc teraz jest leniwy; aby uzyskać pierwsze trafienie w katalogu plików 10M, skanujesz tylko do pierwszego trafienia. A nawet pre-3.6, jeśli używasz glob metody bez symboli wieloznacznych, funkcja jest inteligentna: wie, że możesz mieć tylko jedno trafienie, więc to upraszcza globbing do sprawiedliwego os.path.isdir lub os.path.lexists (w zależności od tego, czy ścieżka się kończy /). - ShadowRanger
Ta druga część mojego komentarza (nie-wieloznaczny globbing nie powoduje iteracji folderu i nigdy go nie ma) nie oznacza, że ​​jest to doskonałe rozwiązanie problemu (wolniejsze niż bezpośrednie wywoływanie os.path.isdir lub os.path.lexist ponieważ jest to pakiet wywołań funkcji poziomu języka Python i operacji łańcuchowych, zanim zdecyduje, że wydajna ścieżka jest możliwa do wykonania, ale bez dodatkowego wywołania systemowego lub operacji we / wy, która jest wolniejsza o rząd wielkości). - ShadowRanger


Python 3.4+ ma obiektowy moduł ścieżki: pathlib. Korzystając z tego nowego modułu, możesz sprawdzić, czy plik istnieje w następujący sposób:

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żesz (i zazwyczaj powinno) nadal używać a try/except blokuj podczas otwierania plików:

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

Moduł pathlib zawiera wiele fajnych rzeczy: wygodne globowanie, sprawdzanie właściciela pliku, łatwiejsze łączenie ścieżek itp. Warto to sprawdzić. Jeśli używasz starszego Pythona (wersja 2.6 lub nowsza), nadal możesz zainstalować pathlib za pomocą pip:

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

Następnie zaimportuj go w następujący sposób:

# Older Python versions
import pathlib2 as pathlib

121
2018-02-08 02:38