ฉันจะตรวจสอบว่ามีไฟล์อยู่โดยไม่มีข้อยกเว้นได้อย่างไร


5604

ฉันจะตรวจสอบว่าไฟล์มีอยู่หรือไม่โดยไม่ใช้tryคำสั่งได้อย่างไร


2
นี่น่าจะเป็นการอภิปรายแบบ EAFP แบบคลาสสิกกับการอภิปรายของ LBYL ดูตัวอย่างคำถามที่เกี่ยวข้องนี้: stackoverflow.com/questions/1835756/using-try-vs-if-in-python
matth

นอกจากนี้ยังมีความเกี่ยวข้องหากคุณต้องการทราบว่ามีอยู่ในดิสก์ (ไม่ว่าโดยตรงหรือเป็นลิงก์สัญลักษณ์) หากคุณสามารถอ่านจากมันหรือถ้าคุณสามารถเขียนลงไป
Thorbjørn Ravn Andersen

คำตอบ:


5153

หากเหตุผลที่คุณตรวจสอบคือเพื่อให้คุณสามารถทำสิ่งต่างif file_exists: open_it()ๆ มันปลอดภัยกว่าที่จะใช้tryความพยายามในการเปิด การตรวจสอบและจากนั้นเปิดความเสี่ยงที่ไฟล์จะถูกลบหรือย้ายหรือบางสิ่งบางอย่างระหว่างเมื่อคุณตรวจสอบและเมื่อคุณพยายามที่จะเปิด

หากคุณไม่ได้วางแผนที่จะเปิดไฟล์ทันทีคุณสามารถใช้ os.path.isfile

ส่งคืนTrueถ้าเส้นทางเป็นไฟล์ปกติที่มีอยู่ สิ่งนี้ตามลิงก์สัญลักษณ์ดังนั้นทั้งislink ()และisfile ()อาจเป็นจริงสำหรับพา ธ เดียวกัน

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

หากคุณต้องแน่ใจว่าเป็นไฟล์

เริ่มต้นด้วย Python 3.4 pathlibโมดูลนำเสนอวิธีการเชิงวัตถุ (backported pathlib2ใน Python 2.7):

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

คุณยังสามารถใช้resolve(strict=True)ในtryบล็อก:

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

40
ที่เกี่ยวข้องกับคำพูดแรก (ใช้ "ลอง" ถ้าตรวจสอบก่อนที่จะเปิด) น่าเสียดายที่นี่จะไม่ทำงานถ้าคุณต้องการที่จะเปิดสำหรับการต่อท้ายตรวจสอบให้แน่ใจว่ามันมีอยู่ก่อนเนื่องจากโหมด 'a' จะสร้างถ้าไม่มี
makapuf

6
โปรดทราบว่าFileNotFoundErrorมีการนำมาใช้ใน Python 3 หากคุณต้องการรองรับ Python 2.7 และ Python 3 คุณสามารถใช้IOErrorแทน ( FileNotFoundErrorคลาสย่อยใด) stackoverflow.com/a/21368457/1960959
scottclowe

7
@makapuf คุณสามารถเปิดมันเพื่อ "อัพเดท" ( open('file', 'r+')) แล้วหาทางจบ
kyrill

2
@kyrill open-and-find-to-the-end ไม่ได้เป็นสิ่งเดียวกับ open-for-ผนวก (อย่างน้อยในระบบ posix) "โหมดต่อท้าย" จะถูกเขียนไปยังจุดสิ้นสุดของไฟล์อย่างถูกต้องเสมอแม้ว่าสิ่งอื่น ๆ จะแก้ไขไฟล์ระหว่างเมื่อมันถูกเปิดและเมื่อการเขียนเกิดขึ้น การเปิดเพื่อเขียน / อัปเดตและค้นหาความเสี่ยงท้ายทำให้ข้อมูลไฟล์เสียหายหากมีหลายสิ่งพยายามเขียนไปยังไฟล์เดียวกันในเวลาเดียวกัน น่าเสียดายที่ฉันเชื่อว่าวิธีเดียวที่ปลอดภัยต่อสภาพการแข่งขันเพื่อเปิดต่อท้ายในขณะที่มั่นใจว่าไฟล์นั้นมีอยู่ก่อนคือใช้รูทีน os.open () ระดับล่างแทน (O_APPEND โดยไม่มี O_CREAT)
Foogod

1
@ LorinczyZsigmond ที่ดูเหมือนว่าเป็นพฤติกรรมที่ขึ้นอยู่กับการนำไปใช้งาน สนใจที่จะแบ่งปันแหล่งที่มาหรือไม่?
kyrill

2111

คุณมีos.path.existsฟังก์ชั่น:

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

สิ่งนี้จะส่งคืนTrueทั้งไฟล์และไดเรกทอรี แต่คุณสามารถใช้แทนได้

os.path.isfile(file_path)

เพื่อทดสอบว่าเป็นไฟล์เฉพาะหรือไม่ มันติดตาม symlinks


965

ซึ่งแตกต่างจากisfile(), exists()จะกลับTrueไดเรกทอรี ดังนั้นขึ้นอยู่กับว่าคุณต้องการเพียงไฟล์ธรรมดาหรือยังไดเรกทอรีที่คุณจะใช้หรือisfile() exists()นี่คือเอาท์พุท REPL แบบง่าย ๆ :

>>> os.path.isfile("/etc/password.txt")
True
>>> os.path.isfile("/etc")
False
>>> os.path.isfile("/does/not/exist")
False
>>> os.path.exists("/etc/password.txt")
True
>>> os.path.exists("/etc")
True
>>> os.path.exists("/does/not/exist")
False


320

ใช้os.path.isfile()กับos.access():

import os

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

60
การมีหลายเงื่อนไขบางเงื่อนไขไม่ฟุ่มเฟือยชัดเจนน้อยกว่าและชัดเจน
Wim

10
มันยังซ้ำซ้อน หากไฟล์ไม่มีอยู่os.access()จะส่งคืนค่าเท็จ
user207421

9
@EJP ในไฟล์ linux สามารถมีอยู่ แต่ไม่สามารถเข้าถึงได้
e-info128

8
ตั้งแต่คุณimport osคุณไม่จำเป็นต้องอีกครั้งขณะที่มันมีอยู่แล้วเป็นส่วนหนึ่งของimport os.path osคุณเพียงแค่ต้องนำเข้าos.pathถ้าคุณจะใช้ฟังก์ชั่นจากos.pathและไม่ได้มาจากosตัวเองเพื่อนำเข้าสิ่งเล็ก ๆ แต่เมื่อคุณใช้os.accessและos.R_OKการนำเข้าที่สองไม่จำเป็น
ตลก

286
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

2
โดยทั่วไปแล้วการฝึกชื่อตัวแปรไม่ดีเหมือนกับชื่อวิธี
Homunculus Reticulli

245

แม้ว่าวิธีที่เป็นไปได้เกือบทุกอย่างจะมีการระบุไว้ใน (อย่างน้อยหนึ่งใน) คำตอบที่มีอยู่ (เช่นสิ่งที่ระบุเฉพาะPython 3.4ถูกเพิ่ม) ฉันจะพยายามจัดกลุ่มทุกอย่างด้วยกัน

หมายเหตุ : รหัสห้องสมุดPythonมาตรฐานทุกชิ้นที่ฉันจะโพสต์เป็นของรุ่น3.5.3 3.5.3

คำแถลงปัญหา :

  1. ตรวจสอบไฟล์ ( พิสูจน์ได้ : มีโฟลเดอร์ (ไฟล์ "พิเศษ")) อยู่ด้วย
  2. อย่าใช้บล็อกลอง / ยกเว้น / อื่น / ในที่สุด

แนวทางแก้ไขที่เป็นไปได้ :

  1. [Python 3]: os.path ที่มีอยู่ ( เส้นทาง ) (ตรวจสอบสมาชิกในครอบครัวฟังก์ชั่นอื่น ๆ เช่นos.path.isfile, os.path.isdir, os.path.lexistsพฤติกรรมที่แตกต่างกันเล็กน้อย)

    os.path.exists(path)

    ส่งคืนTrueหากพา ธอ้างถึงพา ธที่มีอยู่หรือตัวอธิบายไฟล์ที่เปิด ส่งคืนFalseสำหรับลิงก์สัญลักษณ์ที่ใช้งานไม่ได้ ในบางแพลตฟอร์มฟังก์ชั่นนี้อาจส่งคืนFalseหากไม่ได้รับอนุญาตให้เรียกใช้os.stat ()ในไฟล์ที่ร้องขอแม้ว่าเส้นทางจะมีอยู่จริง

    ทุกอย่างดี แต่ถ้าทำตามต้นไม้นำเข้า:

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

      • genericpath.py , บรรทัด~ # 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

    เป็นเพียงลอง / ยกเว้นบล็อกรอบ[Python 3]: os สถิติ ( เส้นทาง, *, dir_fd = ไม่มี follow_symlinks = True ) ดังนั้นรหัสของคุณคือลอง / ยกเว้นฟรี แต่ลดลงในกรอบที่มี (อย่างน้อย) หนึ่งบล็อคดังกล่าว นอกจากนี้ยังใช้กับ funcs อื่น ๆ ( รวมถึง os.path.isfile )

    1.1 [Python 3]: เส้นทาง is_file ()

    • มันเป็นวิธีที่นักเล่น (และงูหลามมากขึ้น) ในการจัดการเส้นทางแต่
    • ภายใต้ฝากระโปรงก็ไม่ว่าสิ่งเดียวกัน ( pathlib.pyสาย~ # 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 3]: ด้วยผู้จัดการบริบทคำสั่ง ทั้ง:

    • สร้างหนึ่ง:

      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 ...)
      • และการใช้งานของมัน - ฉันจะทำซ้ำos.path.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 3]: contextlib ปราบปราม ( * ข้อยกเว้น ) - ซึ่งได้รับการออกแบบมาโดยเฉพาะสำหรับการเลือกข้อยกเว้น


    แต่พวกเขาดูเหมือนจะห่อมากกว่าลอง / ยกเว้น / อื่น ๆ / ในที่สุดบล็อกเป็น[หลาม 3]: ผู้ที่มีงบฯ :

    วิธีนี้ช่วยให้ลอง ... ยกเว้น ... ในที่สุดรูปแบบการใช้งานจะถูกห่อหุ้มเพื่อนำมาใช้ใหม่ได้สะดวก

  3. ฟังก์ชันการแวะผ่านของระบบไฟล์ (และค้นหาผลลัพธ์สำหรับรายการที่ตรงกัน)


    เนื่องจากสิ่งเหล่านี้ซ้ำไปซ้ำมาในโฟลเดอร์ (ในกรณีส่วนใหญ่) พวกเขาไม่มีประสิทธิภาพสำหรับปัญหาของเรา (มีข้อยกเว้นเช่นเดียวกับที่ไม่ใช่ wildcarded glob bing - @ShadowRanger ชี้ให้เห็น) ดังนั้นฉันจะไม่ยืนยันพวกเขา ไม่ต้องพูดถึงว่าในบางกรณีอาจจำเป็นต้องดำเนินการกับชื่อไฟล์

  4. [Python 3]: ระบบปฏิบัติการ การเข้าถึง ( เส้นทางโหมด, *, dir_fd = ไม่มี effective_ids = เท็จ follow_symlinks = True )ที่มีพฤติกรรมอยู่ใกล้กับos.path.exists(ที่จริงมันเป็นที่กว้างขึ้นส่วนใหญ่เป็นเพราะ 2 ครั้งอาร์กิวเมนต์)

    • สิทธิ์ผู้ใช้อาจ จำกัด ไฟล์ "การเปิดเผย" ตามที่ระบุในเอกสาร:

      ... ทดสอบว่าผู้ใช้กล่าวอ้างมีการเข้าถึงที่ระบุเพื่อเส้นทาง โหมดควรเป็นF_OKเพื่อทดสอบการมีอยู่ของเส้นทาง ...

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

    ตั้งแต่ผมยังทำงานในCผมใช้วิธีนี้เช่นกันเพราะภายใต้ประทุนมันเรียกพื้นเมืองAPI s (อีกครั้งผ่านทาง"$ {} PYTHON_SRC_DIR /Modules/posixmodule.c" ) แต่มันยังเปิดประตูสำหรับการที่เป็นไปได้ของผู้ใช้ ข้อผิดพลาดและไม่ใช่Python ic เหมือนกับรุ่นอื่น ดังนั้นตามที่ @AaronHall ชี้ให้เห็นอย่างถูกต้องอย่าใช้มันยกเว้นว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่:

    หมายเหตุ : การเรียกAPI เนทีฟ s ยังสามารถทำได้ผ่าน[Python 3]: ctypes - ไลบรารีฟังก์ชันต่างประเทศสำหรับ Pythonแต่โดยส่วนใหญ่แล้วจะซับซ้อนกว่า

    ( เฉพาะWin ): ตั้งแต่vcruntime * ( msvcr * ) .dllส่งออก[MS.Docs]: _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.notexist", os.F_OK)
    -1

    หมายเหตุ :

    • แม้ว่าจะไม่ใช่วิธีปฏิบัติที่ดีฉันใช้os.F_OKในการโทร แต่นั่นเป็นเพียงเพื่อความชัดเจน (ค่าของมันคือ0 )
    • ฉันใช้_waccessเพื่อให้รหัสเดียวกันทำงานบนPython3และPython2 (แม้จะเป็นunicode)ความแตกต่างที่เกี่ยวข้องกับ )
    • แม้ว่าเป้าหมายนี้จะเป็นพื้นที่ที่เฉพาะเจาะจงแต่ก็ไม่ได้กล่าวถึงในคำตอบก่อนหน้าใด ๆ


    คู่Lnx ( Ubtu (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"/tmp.notexist", os.F_OK)
    -1

    หมายเหตุ :

    • แทนที่จะ hardcoding libcเส้นทาง 's ( '/lib/x86_64-linux-gnu/libc.so.6' ) ซึ่งอาจ (และส่วนใหญ่มีแนวโน้มจะ) แตกต่างกันในระบบไม่มี (หรือสตริงว่างเปล่า) สามารถส่งผ่านไปCDLLคอนสตรัค ( ctypes.CDLL(None).access(b"/tmp", os.F_OK)) ตามที่[man7]: DLOPEN (3) :

      หากชื่อไฟล์เป็น NULL ดังนั้นหมายเลขอ้างอิงที่ส่งคืนจะเป็นของโปรแกรมหลัก เมื่อได้รับการdlsym () จับนี้จะทำให้การค้นหาสำหรับสัญลักษณ์ในโปรแกรมหลักตามด้วยวัตถุที่ใช้ร่วมกันทั้งหมดที่โหลดโปรแกรมที่เริ่มต้นและวัตถุจากนั้นร่วมกันทั้งหมดโหลดโดยdlopen () กับธงRTLD_GLOBAL

      • โปรแกรมหลัก (ปัจจุบัน) ( python ) เชื่อมโยงกับlibcดังนั้นสัญลักษณ์ (รวมถึงการเข้าถึง ) จะถูกโหลด
      • สิ่งนี้จะต้องได้รับการจัดการด้วยความระมัดระวังเนื่องจากฟังก์ชั่นเช่นmain , Py_Mainและอื่น ๆ (ทั้งหมด) มีอยู่; เรียกพวกเขาอาจมีผลร้าย (ในโปรแกรมปัจจุบัน)
      • สิ่งนี้ยังไม่นำไปใช้กับWin (แต่นั่นไม่ใช่เรื่องใหญ่เช่นนี้เนื่องจากmsvcrt.dllอยู่ใน"% SystemRoot% \ System32"ซึ่งอยู่ใน% PATH%โดยปริยาย) ฉันต้องการทำสิ่งต่อไปและทำซ้ำพฤติกรรมนี้ในWin (และส่ง patch) แต่เมื่อปรากฎ[MS.Docs]: GetProcAddress ฟังก์ชั่นเท่านั้น "เห็น" สัญลักษณ์ที่ส่งออกดังนั้นถ้ามีคนประกาศฟังก์ชั่นในปฏิบัติการหลัก ในฐานะที่เป็น__declspec(dllexport)(ทำไมบนโลกที่บุคคลทั่วไปจะทำเช่นนั้น?) โปรแกรมหลักสามารถโหลดได้ แต่ใช้งานไม่ได้
  5. ติดตั้งโมดูลบุคคลที่สามที่มีความสามารถของระบบไฟล์

    ส่วนใหญ่แล้วจะใช้วิธีใดวิธีหนึ่งข้างต้น (อาจมีการปรับแต่งเล็กน้อย)
    ตัวอย่างหนึ่งจะเป็น (อีกครั้งเฉพาะWin ) [GitHub]: mhammond / pywin32 - Python สำหรับ Windows (pywin32) ส่วนขยายซึ่งเป็นPython wrapper เหนือWINAPI s

    แต่เนื่องจากนี่เป็นวิธีแก้ปัญหาฉันจึงหยุดที่นี่

  6. วิธีแก้ปัญหาอื่น (lame) ( gainarie ) คือ (ตามที่ฉันต้องการเรียกว่า) แนวทางsysadmin : ใช้Pythonเป็น wrapper เพื่อรันคำสั่งเชลล์

    • ชนะ :

      (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

บรรทัดล่างสุด :

  • ทำใช้ลอง / ยกเว้น / อื่น ๆ / ในที่สุดบล็อกเพราะพวกเขาสามารถป้องกันไม่ให้คุณทำงานเป็นชุดของปัญหาที่น่ารังเกียจ ตัวอย่างที่ฉันคิดได้ก็คือประสิทธิภาพ: บล็อกดังกล่าวมีราคาแพงดังนั้นอย่าพยายามวางไว้ในรหัสที่ควรรันหลายแสนครั้งต่อวินาที (แต่เนื่องจาก (ในกรณีส่วนใหญ่) มันเกี่ยวข้องกับการเข้าถึงดิสก์ มันจะไม่เป็นอย่างนั้น)

บันทึกสุดท้าย :

  • ฉันจะพยายามทำให้มันทันสมัย, คำแนะนำใด ๆ ยินดีต้อนรับฉันจะรวมสิ่งที่มีประโยชน์ที่จะเกิดขึ้นในคำตอบ

3
คุณสามารถอธิบายเพิ่มเติมเกี่ยวกับคำแถลงนี้ได้ไหม? "แม้ว่าจะไม่ใช่วิธีปฏิบัติที่ดีฉันใช้ os.F_OK ในการโทร แต่นั่นก็เพื่อความชัดเจน (ค่าของมันคือ 0)"
sk8asd123

6
@ sk8asd123: ชนิดของยากที่จะดูในความคิดเห็น: โดยทั่วไปแล้วมันเป็นการดีที่สุดที่จะใช้ค่าคงที่กับฟังก์ชั่นที่มาพร้อมกับพวกเขา ที่ใช้เมื่อทำงานกับหลายโมดูลที่กำหนดค่าคงที่เดียวกันเนื่องจากบางโมดูลอาจไม่ทันสมัยและเป็นการดีที่สุดสำหรับฟังก์ชันและค่าคงที่ที่จะซิงค์ เมื่อทำงานกับctypes (เรียกใช้ฟังก์ชันโดยตรง) ฉันควรกำหนดค่าคงที่ (จากMSDN ) หรือไม่ใช้ค่าคงที่เลย เป็นเพียงแนวทางที่ฉันใช้ใน 99.9% มันอาจทำให้ไม่มีความแตกต่าง (ตามหน้าที่)
CristiFati

3
@CristiFati: ตั้งแต่ 3.6 glob.iglob(และglob.globเช่นกัน) ขึ้นอยู่กับos.scandirดังนั้นตอนนี้มันขี้เกียจ หากต้องการได้รับความนิยมครั้งแรกในไดเรกทอรีของไฟล์ 10M คุณจะสแกนเพียงจนกว่าจะถึงการเข้าชมครั้งแรก และแม้กระทั่ง pre-3.6 หากคุณใช้globวิธีที่ไม่มี wildcard ใด ๆ ฟังก์ชั่นนั้นชาญฉลาด: มันรู้ว่าคุณสามารถกดได้เพียงครั้งเดียวเท่านั้นดังนั้นมันos.path.isdiros.path.lexistsจึงทำให้การหมุนเป็นวงกลมง่ายขึ้นหรือเพียงแค่ (ขึ้นอยู่กับเส้นทางที่สิ้นสุด/)
ShadowRanger

3
ส่วนที่สองของความคิดเห็นของฉัน (ที่ไม่ใช่สัญลักษณ์ตัวแทนไม่ได้วนซ้ำโฟลเดอร์จริง ๆ และไม่เคยมี) หมายความว่ามันเป็นวิธีการแก้ปัญหาที่มีประสิทธิภาพอย่างสมบูรณ์แบบ (ช้ากว่าการโทรโดยตรงos.path.isdirหรือos.path.lexistเนื่องจากมันเป็นการเรียกฟังก์ชั่น การดำเนินการก่อนที่จะตัดสินใจเส้นทางที่มีประสิทธิภาพเป็นไปได้ แต่ไม่มีการเรียกระบบเพิ่มเติมหรืองาน I / O ซึ่งเป็นคำสั่งของขนาดช้าลง)
ShadowRanger

154

นี่เป็นวิธีที่ง่ายที่สุดในการตรวจสอบว่ามีไฟล์อยู่หรือไม่ เพียงเพราะไฟล์ที่มีอยู่เมื่อคุณตรวจสอบไม่ได้รับประกันว่าจะมีเมื่อคุณต้องการที่จะเปิด

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

17
ตราบใดที่คุณตั้งใจจะเข้าถึงไฟล์เงื่อนไขการแข่งขันจะมีอยู่ไม่ว่าโปรแกรมของคุณจะถูกสร้างขึ้นมาอย่างไร โปรแกรมของคุณไม่สามารถรับประกันได้ว่ากระบวนการอื่นในคอมพิวเตอร์ไม่ได้แก้ไขไฟล์ มันเป็นสิ่งที่เอริค Lippert หมายถึงเป็นข้อยกเว้นจากภายนอก คุณไม่สามารถหลีกเลี่ยงได้โดยตรวจสอบการมีอยู่ของไฟล์ไว้ก่อน
Isaac Supeene

@IsaacSupeene แนวทางปฏิบัติที่ดีที่สุดคือการทำให้หน้าต่างของการดำเนินการ (ไฟล์) มีขนาดเล็กที่สุดเท่าที่จะทำได้ตามด้วยการจัดการข้อยกเว้นที่เหมาะสม
4323 un33k

145

งูหลาม 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 ขึ้นไป) คุณยังสามารถติดตั้ง pathlib ด้วย pip ได้:

# 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

124

ชอบคำสั่งลอง ถือว่าเป็นสไตล์ที่ดีกว่าและหลีกเลี่ยงสภาพการแข่งขัน

อย่าใช้คำพูดของฉันมัน มีการสนับสนุนมากมายสำหรับทฤษฎีนี้ นี่คือสองสาม:


3
โปรดเพิ่มแหล่งข้อมูลที่ดีกว่าเพื่อรองรับคำสั่งของคุณ
BlueTrin

11
ลิงก์อ้างถึงเงื่อนไขการหลีกเลี่ยงการแข่งขัน (การสนับสนุน apple dev) ไม่สนับสนุนคำตอบของคุณ มันเกี่ยวข้องกับการใช้ไฟล์ชั่วคราวที่มีข้อมูลที่ละเอียดอ่อนบนระบบปฏิบัติการที่ออกแบบมาไม่ดีซึ่งไม่เหมาะสมกับไฟล์ / ไดเรกทอรีชั่วคราวผ่านการอนุญาตที่ จำกัด ใช้try...exceptไม่ได้ช่วยแก้ปัญหาว่าปัญหาอยู่แล้ว
jstine

ปัญหาของวิธีนี้คือถ้าคุณมีส่วนสำคัญของรหัสขึ้นอยู่กับไฟล์ที่ไม่มีอยู่การใส่ไว้ในexcept:clause จะทำให้ข้อยกเว้นที่เกิดขึ้นในส่วนนี้ของรหัสของคุณจะทำให้เกิดข้อความสับสน การประมวลผลของคนแรก.)
Camion

119

ฉันจะตรวจสอบว่ามีไฟล์อยู่หรือไม่โดยใช้ Python โดยไม่ต้องใช้คำสั่ง try

ตอนนี้มีให้ตั้งแต่ Python 3.4 นำเข้าและสร้างอินสแตนซ์Pathวัตถุด้วยชื่อไฟล์และตรวจสอบis_fileวิธีการ (โปรดทราบว่าสิ่งนี้จะคืนค่า True สำหรับ symlink ที่ชี้ไปที่ไฟล์ปกติเช่นกัน):

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

หากคุณใช้ Python 2 คุณสามารถย้อนกลับโมดูล pathlib จาก pypi pathlib2หรือตรวจสอบisfileจากos.pathโมดูลได้:

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

ตอนนี้อาจเป็นคำตอบที่ดีที่สุดในทางปฏิบัติตรงนี้ แต่ก็มีความเป็นไปได้ที่สภาพการแข่งขัน (ขึ้นอยู่กับสิ่งที่คุณพยายามจะทำให้สำเร็จ) และความจริงที่ว่าการใช้งานพื้นฐานนั้นใช้ a tryแต่ Python ใช้tryทุกที่

เนื่องจาก Python ใช้tryทุกที่จึงไม่มีเหตุผลที่จะหลีกเลี่ยงการนำไปใช้งาน

แต่ส่วนที่เหลือของคำตอบนี้พยายามพิจารณาข้อแม้เหล่านี้

อีกต่อไปคำตอบอวดรู้มากขึ้น

มีตั้งแต่ Python 3.4 ใช้ใหม่วัตถุในPath pathlibโปรดทราบว่า.existsไม่ถูกต้องเนื่องจากไดเรกทอรีไม่ใช่ไฟล์ (ยกเว้นในระบบยูนิกซ์ที่ทุกอย่างเป็นไฟล์)

>>> 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คุณเพียงแค่พยายามอ่านไฟล์ของคุณโดยคาดหวังว่ามันจะอยู่ที่นั่นและหากไม่ได้คุณก็จะได้รับการยกเว้น

หากคุณต้องการตรวจสอบว่ามีไฟล์อยู่ก่อนที่คุณจะพยายามอ่านและคุณอาจกำลังลบไฟล์จากนั้นคุณอาจใช้หลายเธรดหรือกระบวนการหรือโปรแกรมอื่นรู้เกี่ยวกับไฟล์นั้นและสามารถลบได้ - คุณเสี่ยงต่อการเกิดสภาพการแข่งขันที่ถ้าคุณตรวจสอบมันมีอยู่แล้วเพราะคุณแล้วการแข่งรถที่จะเปิดมันก่อนที่จะสภาพ (การดำรงอยู่ของมัน) การเปลี่ยนแปลง

สภาพการแข่งขันยากที่จะดีบั๊กเนื่องจากมีหน้าต่างเล็ก ๆ ซึ่งพวกเขาสามารถทำให้โปรแกรมของคุณล้มเหลว

แต่ถ้านี่คือแรงบันดาลใจของคุณคุณสามารถรับค่าของtryคำสั่งโดยใช้ตัวsuppressจัดการบริบท

หลีกเลี่ยงสภาพการแข่งขันโดยไม่ต้องลองคำสั่ง: 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()
... 
>>> 

สำหรับไพ ธ อนก่อนหน้านี้คุณสามารถม้วนตัวเองsuppressได้ แต่จะไม่มีความtryละเอียดมากกว่าด้วย ฉันเชื่อว่านี่เป็นคำตอบเดียวที่ไม่ได้ใช้tryในระดับใด ๆ ใน Pythonที่สามารถใช้กับ Python 3.4 ก่อนได้เพราะใช้ตัวจัดการบริบทแทน:

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)

จากเอกสาร :

os.path.isfile(path)

ส่งคืน True ถ้าเส้นทางเป็นไฟล์ปกติที่มีอยู่ นี่ตามลิงก์สัญลักษณ์ดังนั้นทั้งสองislink()และisfile()สามารถเป็นจริงสำหรับเส้นทางเดียวกัน

แต่ถ้าคุณตรวจสอบแหล่งที่มาของฟังก์ชั่นนี้คุณจะเห็นว่ามันใช้คำสั่งลอง:

# 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นอกจากนี้ยังได้รับความทุกข์จากปัญหาเดียวกันสภาพการแข่งขันที่เป็น จากเอกสาร :

หมายเหตุ: การใช้ 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") แต่มันยังเปิดประตูสำหรับข้อผิดพลาดที่อาจเกิดขึ้นกับผู้ใช้ :

คำตอบนี้บอกว่าชอบวิธีการที่ไม่มีข้อผิดพลาดและไม่มีข้อผิดพลาดโดยไม่มีเหตุผล ดูเหมือนว่าจะกระตุ้นให้ผู้ใช้ใช้ API ระดับต่ำโดยไม่เข้าใจ

นอกจากนี้ยังสร้างตัวจัดการบริบทซึ่งกลับมาโดยไม่มีเงื่อนไขTrueช่วยให้ข้อยกเว้นทั้งหมด (รวมถึงKeyboardInterruptและSystemExit!) ผ่านไปอย่างเงียบ ๆ ซึ่งเป็นวิธีที่ดีในการซ่อนข้อบกพร่อง

สิ่งนี้ดูเหมือนจะกระตุ้นให้ผู้ใช้ยอมรับการปฏิบัติที่ไม่ดี


87
import os
#Your path here e.g. "C:\Program Files\text.txt"
#For access purposes: "C:\\Program Files\\text.txt"
if os.path.exists("C:\..."):   
    print "File found!"
else:
    print "File not found!"

การนำเข้าosช่วยให้นำทางและดำเนินการมาตรฐานกับระบบปฏิบัติการของคุณได้ง่ายขึ้น

สำหรับการอ้างอิงดูที่วิธีตรวจสอบว่ามีไฟล์อยู่ด้วย Python หรือไม่

หากคุณต้องการการดำเนินงานในระดับสูง, shutilการใช้งาน


9
คำตอบนี้ผิด os.path.existsคืนค่าจริงสำหรับสิ่งที่ไม่ใช่ไฟล์เช่นไดเรกทอรี สิ่งนี้ให้ผลบวกที่ผิดพลาด ดูคำตอบอื่น ๆ os.path.isfileที่แนะนำ
Chris Johnson

84

การทดสอบสำหรับไฟล์และโฟลเดอร์ที่มี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

72

ในปี 2559 วิธีที่ดีที่สุดยังคงใช้อยู่os.path.isfile:

>>> os.path.isfile('/path/to/some/file.txt')

หรือใน Python 3 คุณสามารถใช้pathlib:

import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
    ...

3
ฉันขอ: สิ่งที่เป็นประโยชน์ของการใช้โมดูล 'pathlib' แทนโมดูล 'os' ใน python3 สำหรับการตรวจสอบนี้
Joko

3
pathlibเป็นวิธีการแก้ปัญหา OOP ของไพ ธ อนสำหรับเส้นทาง คุณสามารถทำอะไรได้มากกว่านี้อีกแล้ว หากคุณเพียงแค่ต้องตรวจสอบการดำรงอยู่ของข้อได้เปรียบไม่ใหญ่มาก
KaiBuxe

65

ดูเหมือนจะไม่มีความแตกต่างในการใช้งานที่มีความหมายระหว่างลอง / ยกเว้นและ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'

หากคุณต้องการล็อคไฟล์นั่นเป็นเรื่องอื่น


3
คำตอบนี้ผิด os.path.existsคืนค่าจริงสำหรับสิ่งที่ไม่ใช่ไฟล์เช่นไดเรกทอรี สิ่งนี้ให้ผลบวกที่ผิดพลาด ดูคำตอบอื่น ๆ os.path.isfileที่แนะนำ
คริสจอห์นสัน

6
ในตัวอย่างที่สามของคุณฉันสร้างลิงค์ที่filepathมีจังหวะเวลาที่เหมาะสมและBAMคุณเขียนทับไฟล์เป้าหมาย คุณควรทำopen(filepath, 'wx')ในtry...exceptบล็อกเพื่อหลีกเลี่ยงปัญหา
สเปกตรัม

1
ในตัวอย่างที่สองของคุณอย่างน้อยใน Windows คุณจะได้รับOSErrorถ้าfilepath + '.old'มีอยู่แล้ว: "บน Windows หาก dst มีอยู่แล้ว OSError จะเพิ่มขึ้นแม้ว่าจะเป็นไฟล์ แต่อาจไม่มีวิธีในการเปลี่ยนชื่ออะตอมมิกเมื่อ dst ตั้งชื่อไฟล์ที่มีอยู่ "
Tom Myddeltyn

@TomMyddeltyn: ตั้งแต่ Python 3.3 สามารถos.replaceทำการแทนที่ไฟล์ปลายทางได้อย่างเงียบ ๆ (มันเหมือนกับos.renameพฤติกรรมของ Linux) (จะมีข้อผิดพลาดเฉพาะเมื่อชื่อปลายทางนั้นมีอยู่และเป็นไดเรกทอรี) คุณติดอยู่ที่ 2.x แต่ผู้ใช้ Py3 มีตัวเลือกที่ดีมาหลายปีแล้ว
ShadowRanger

ในrenameตัวอย่างเช่นมันก็ยังคงควรจะทำด้วย/try (หรือPython สมัยใหม่) เป็นอะตอม ทำให้มันตรวจสอบแล้วเปลี่ยนชื่อแนะนำการแข่งขันที่ไม่จำเป็นและการเรียกระบบเพิ่มเติม เพิ่งทำexceptos.renameos.replacetry: os.replace(filepath, filepath + '.old') except OSError: pass
ShadowRanger

59

คุณสามารถลอง (ปลอดภัยกว่า):

try:
    # http://effbot.org/zone/python-with-statement.htm
    # 'with' is safer to open a file
    with open('whatever.txt') as fh:
        # Do something with 'fh'
except IOError as e:
    print("({})".format(e))

ouput จะเป็น:

([Errno 2] ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว: 'Anything.txt')

จากนั้นขึ้นอยู่กับผลลัพธ์โปรแกรมของคุณสามารถทำงานต่อจากที่นั่นหรือคุณสามารถโค้ดเพื่อหยุดถ้าคุณต้องการ


18
คำถามเดิมถามหาวิธีแก้ปัญหาที่ไม่ได้ใช้try
rrs

5
คำตอบนี้พลาดจุดของ OP การตรวจสอบว่ามีไฟล์อยู่ไม่เหมือนกับการตรวจสอบว่าคุณสามารถเปิดได้หรือไม่ จะมีหลายกรณีที่มีไฟล์อยู่ แต่ด้วยเหตุผลหลายประการคุณไม่สามารถเปิดได้
Chris Johnson

51

แม้ว่าฉันมักจะแนะนำให้ใช้tryและexceptข้อความต่างๆต่อไปนี้เป็นความเป็นไปได้บางอย่างสำหรับคุณ (รายการโปรดส่วนตัวของฉันกำลังใช้os.access):

  1. ลองเปิดไฟล์:

    การเปิดไฟล์จะตรวจสอบการมีอยู่ของไฟล์เสมอ คุณสามารถสร้างฟังก์ชั่นได้เช่น:

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

    ถ้าเป็นเท็จมันจะหยุดการทำงานด้วย IOError หรือ OSError ใน Python รุ่นที่ใหม่กว่า ในการตรวจจับข้อยกเว้นคุณต้องใช้การลองยกเว้นข้อ แน่นอนคุณสามารถใช้tryคำสั่งยกเว้น ` เป็นเช่นนั้นเสมอ (ขอบคุณ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มันจะตรวจสอบการมีอยู่ของเส้นทาง อย่างไรก็ตามการใช้สิ่งนี้จะสร้างช่องโหว่ด้านความปลอดภัยเนื่องจากบางคนสามารถโจมตีไฟล์ของคุณโดยใช้เวลาระหว่างการตรวจสอบการอนุญาตและการเปิดไฟล์ คุณควรไปที่การเปิดไฟล์โดยตรงแทนที่จะตรวจสอบการอนุญาต ( EAFPเทียบกับLBYP ) หากคุณไม่ต้องการเปิดไฟล์ในภายหลังและตรวจสอบการมีอยู่ของไฟล์เท่านั้นคุณสามารถใช้ไฟล์นี้ได้

    อย่างไรก็ตามที่นี่:

    >>> import os
    >>> os.access("/is/a/file.txt", os.F_OK)
    True

ฉันควรพูดถึงว่ามีสองวิธีที่คุณจะไม่สามารถยืนยันการมีอยู่ของไฟล์ได้ ไม่ว่าปัญหาจะได้รับหรือpermission denied no such file or directoryหากคุณพบข้อผิดพลาดIOErrorให้ตั้งค่าIOError as e(เช่นตัวเลือกแรกของฉัน) จากนั้นพิมพ์print(e.args)เพื่อให้คุณสามารถระบุปัญหาของคุณได้ ฉันหวังว่ามันจะช่วย! :)


51

วันที่: 2017/12/04

คำตอบที่เป็นไปได้ทั้งหมดนั้นมีคำตอบอื่น ๆ

วิธีที่ใช้งานง่ายและสามารถตรวจสอบได้ว่ามีไฟล์อยู่หรือไม่:

import os
os.path.isfile('~/file.md')  # Returns True if exists, else False
# additionaly check a dir
os.path.isdir('~/folder')  # Returns True if the folder exists, else False
# check either a dir or a file
os.path.exists('~/file')

ฉันทำ cheatsheet ครบถ้วนสมบูรณ์สำหรับการอ้างอิงของคุณ:

#os.path methods in exhaustive cheatsheet
{'definition': ['dirname',
               'basename',
               'abspath',
               'relpath',
               'commonpath',
               'normpath',
               'realpath'],
'operation': ['split', 'splitdrive', 'splitext',
               'join', 'normcase'],
'compare': ['samefile', 'sameopenfile', 'samestat'],
'condition': ['isdir',
              'isfile',
              'exists',
              'lexists'
              'islink',
              'isabs',
              'ismount',],
 'expand': ['expanduser',
            'expandvars'],
 'stat': ['getatime', 'getctime', 'getmtime',
          'getsize']}

37

หากไฟล์สำหรับเปิดคุณสามารถใช้หนึ่งในเทคนิคต่อไปนี้:

with open('somefile', 'xt') as f: #Using the x-flag, Python3.3 and above
    f.write('Hello\n')

if not os.path.exists('somefile'): 
    with open('somefile', 'wt') as f:
        f.write("Hello\n")
else:
    print('File already exists!')

UPDATE

เพียงเพื่อหลีกเลี่ยงความสับสนและตามคำตอบที่ฉันได้คำตอบปัจจุบันจะค้นหาไฟล์หรือไดเรกทอรีที่มีชื่อที่กำหนด


9
คำตอบนี้ผิด os.path.existsคืนค่าจริงสำหรับสิ่งที่ไม่ใช่ไฟล์เช่นไดเรกทอรี สิ่งนี้ให้ผลบวกที่ผิดพลาด ดูคำตอบอื่น ๆ os.path.isfileที่แนะนำ
Chris Johnson

ได้รับปัญหาเชิงบวกที่ผิดพลาดด้วย
Zorglub29

docs.python.org/3/library/os.path.html#os.path.exists ไปที่คำสั่งข้างต้นจาก chris >> os.path.exists (เส้นทาง)> Return True ถ้าเส้นทางหมายถึงเส้นทางที่มีอยู่หรือเปิด อธิบายไฟล์ ส่งคืนค่าเท็จสำหรับลิงก์สัญลักษณ์ที่ใช้งานไม่ได้ ในบางแพลตฟอร์มฟังก์ชั่นนี้อาจส่งคืนค่า False หากไม่ได้รับอนุญาตให้เรียกใช้ os.stat () ในไฟล์ที่ร้องขอแม้ว่าเส้นทางจะมีอยู่จริง เปลี่ยนเป็นเวอร์ชั่น 3.3: ตอนนี้พา ธ สามารถเป็นจำนวนเต็มได้: True ถูกส่งคืนหากเป็น descriptor เปิดไฟล์หรือไม่เช่นนั้นจะเป็นเท็จ เปลี่ยนเป็นเวอร์ชั่น 3.6: ยอมรับวัตถุคล้ายพา ธ
JayRizzo

36

นอกจากนี้os.access():

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

กำลังR_OK, W_OKและ, X_OKแฟล็กเพื่อทดสอบการอนุญาต ( doc )


20
if os.path.isfile(path_to_file):
    try: 
        open(path_to_file)
            pass
    except IOError as e:
        print "Unable to open file"

การยกข้อยกเว้นถือเป็นวิธีการที่ยอมรับได้และ Pythonic สำหรับการควบคุมการไหลในโปรแกรมของคุณ พิจารณาจัดการไฟล์ที่หายไปด้วย IOErrors ในสถานการณ์นี้ข้อยกเว้นของ IOError จะถูกยกขึ้นหากไฟล์มีอยู่ แต่ผู้ใช้ไม่ได้รับอนุญาตให้อ่าน

SRC: http://www.pfinn.net/python-check-if-file-exists.html


3
OP ถามถึงวิธีตรวจสอบว่ามีไฟล์อยู่หรือไม่ เป็นไปได้ที่ไฟล์จะมีอยู่ แต่สำหรับคุณที่จะไม่สามารถเปิดได้ ดังนั้นการใช้การเปิดไฟล์เป็นพร็อกซีเพื่อตรวจสอบว่าไฟล์นั้นมีอยู่ไม่ถูกต้อง: จะมีเนกาทีฟที่เป็นเท็จ
Chris Johnson

19

หากคุณนำเข้า NumPy แล้วเพื่อวัตถุประสงค์อื่น ๆ แล้วมีความจำเป็นต้องนำเข้าห้องสมุดอื่น ๆ เช่นpathlib, os, pathsฯลฯ

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

สิ่งนี้จะคืนค่าจริงหรือเท็จตามการมีอยู่ของมัน


18

try:คุณสามารถเขียนข้อเสนอแนะของไบรอันได้โดยไม่ต้อง

from contextlib import suppress

with suppress(IOError), open('filename'):
    process()

suppressเป็นส่วนหนึ่งของ Python 3.4 ในรุ่นเก่าคุณสามารถเขียนการปราบปรามของคุณเองได้อย่างรวดเร็ว:

from contextlib import contextmanager

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

17

ฉันเป็นผู้เขียนของแพ็คเกจที่มีมานานประมาณ 10 ปีและมีฟังก์ชั่นที่ตอบคำถามนี้โดยตรง โดยทั่วไปถ้าคุณอยู่ในระบบที่ไม่ใช่ Windows จะใช้ในการเข้าถึงPopen findอย่างไรก็ตามถ้าคุณใช้ Windows มันจะทำซ้ำfindกับระบบไฟล์ที่มีประสิทธิภาพ

รหัสที่ตัวเองไม่ได้ใช้tryบล็อก ... ยกเว้นในการกำหนดระบบปฏิบัติการและทำให้พวงมาลัยคุณไป "ยูนิกซ์" สไตล์หรือมือfind buillt findการทดสอบเวลาแสดงให้เห็นว่าtryเร็วกว่าในการกำหนดระบบปฏิบัติการดังนั้นฉันจึงใช้ที่นั่น (แต่ไม่มีที่อื่น)

>>> import pox
>>> pox.find('*python*', type='file', root=pox.homedir(), recurse=False)
['/Users/mmckerns/.python']

และหมอ ...

>>> print pox.find.__doc__
find(patterns[,root,recurse,type]); Get path to a file or directory

    patterns: name or partial name string of items to search for
    root: path string of top-level directory to search
    recurse: if True, recurse down from root directory
    type: item filter; one of {None, file, dir, link, socket, block, char}
    verbose: if True, be a little verbose about the search

    On some OS, recursion can be specified by recursion depth (an integer).
    patterns can be specified with basic pattern matching. Additionally,
    multiple patterns can be specified by splitting patterns with a ';'
    For example:
        >>> find('pox*', root='..')
        ['/Users/foo/pox/pox', '/Users/foo/pox/scripts/pox_launcher.py']

        >>> find('*shutils*;*init*')
        ['/Users/foo/pox/pox/shutils.py', '/Users/foo/pox/pox/__init__.py']

>>>

การใช้งานถ้าคุณสนใจที่จะดูอยู่ที่นี่: https://github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190


17

ตรวจสอบไฟล์หรือไดเรกทอรีที่มีอยู่

คุณสามารถทำตามสามวิธีต่อไปนี้:

หมายเหตุ 1: os.path.isfileใช้สำหรับไฟล์เท่านั้น

import os.path
os.path.isfile(filename) # True if file exists
os.path.isfile(dirname) # False if directory exists

Note2: os.path.existsใช้สำหรับทั้งไฟล์และไดเรกทอรี

import os.path
os.path.exists(filename) # True if file exists
os.path.exists(dirname) #True if directory exists

pathlib.Pathวิธีการ (รวมอยู่ในหลาม 3+, ติดตั้งได้กับ pip สำหรับงูหลาม 2)

from pathlib import Path
Path(filename).exists()

16

การเพิ่มการเปลี่ยนแปลงอีกเล็กน้อยซึ่งไม่ได้สะท้อนให้เห็นอย่างชัดเจนในคำตอบอื่น ๆ

นี้จะจัดการกับกรณีของการ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):

3
if (x) return true; else return false;return xเป็นจริงเพียง return os.path.isfile(file_path)สี่บรรทัดสุดท้ายของคุณจะกลายเป็น return file_path and os.path.isfile(file_path)ในขณะที่เรากำลังที่จะฟังก์ชั่นทั้งสามารถประยุกต์เป็น
Shahbaz

คุณจะต้องระมัดระวังกับในกรณีของreturn x if (x)Python จะพิจารณาสตริงว่างเปล่า False ซึ่งในกรณีนี้เราจะส่งคืนสตริงว่างแทนที่จะเป็นบูล วัตถุประสงค์ของฟังก์ชั่นนี้คือส่งคืนบูลเสมอ
Marcel Wilson

1
จริง อย่างไรก็ตามในกรณีxนี้os.path.isfile(..)มันเป็นบูลที่มีอยู่แล้ว
Shahbaz

os.path.isfile(None)เพิ่มข้อยกเว้นซึ่งเป็นสาเหตุที่ฉันเพิ่มการตรวจสอบถ้า ฉันอาจจะห่อมันด้วยการลอง / ยกเว้นแทน แต่ฉันรู้สึกว่ามันชัดเจนกว่านี้
Marcel Wilson

3
return file_path and os.path.isfile(file_path)
ปีเตอร์วู้ด

15

ต่อไปนี้เป็นคำสั่ง Python 1 บรรทัดสำหรับสภาพแวดล้อมบรรทัดคำสั่ง Linux ฉันพบว่ามันมีประโยชน์มากเพราะฉันไม่ใช่คนทุบตีที่ร้อนแรง

python -c "import os.path; print os.path.isfile('/path_to/file.xxx')"

ฉันหวังว่านี้จะเป็นประโยชน์.


6
การตรวจสอบหนึ่งบรรทัดใน bash: [ -f "${file}" ] && echo "file found" || echo "file not found"(ซึ่งเหมือนกับif [ ... ]; then ...; else ...; fi)
flotzilla

12

คุณสามารถใช้ไลบรารี "OS" ของ Python ได้:

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

5
คำตอบนี้ผิด os.path.existsคืนค่าจริงสำหรับสิ่งที่ไม่ใช่ไฟล์เช่นไดเรกทอรี สิ่งนี้ให้ผลบวกที่ผิดพลาด ดูคำตอบอื่น ๆ os.path.isfileที่แนะนำ
Chris Johnson

@Chris Johnson ฟังก์ชั่น os.path.exists () ตรวจสอบว่ามีเส้นทางอยู่ในระบบหรือไม่ เส้นทางอาจเป็นไดเรกทอรีหรือไฟล์ มันจะทำงานได้ดีในทั้งสองกรณี โปรดลองด้วยตัวอย่าง
Pradip Das

ดังนั้นคำตอบนี้ใช้งานได้ ยิ่งใหญ่ Iffพา ธ ไม่ใช่ของไฟล์ คำถามนั้นเกี่ยวกับอะไร ไม่ใช่
Debosmit Ray

มันขึ้นอยู่กับ. หากเป้าหมายในการพิจารณาการมีอยู่ของ "ไฟล์" คือการค้นหาว่าเส้นทางนั้นมีอยู่แล้วหรือไม่และไม่ใช่เส้นทางที่สามารถจัดเก็บข้อมูลใหม่ได้โดยไม่ต้องลบข้อมูลอื่น ๆ ดังนั้นก็existsถือว่าใช้ได้ หากเป้าหมายคือการตรวจสอบว่ามีความปลอดภัยในการเปิดไฟล์ที่มีอยู่สันนิษฐานว่าการวิจารณ์นั้นเป็นธรรมและมีอยู่จริงนั้นไม่แม่นยำเพียงพอ น่าเสียดายที่ OP ไม่ได้ระบุว่าเป็นเป้าหมายที่ต้องการ (และอาจจะไม่ทำอีกต่อไป)
starturtle

12

ฉันจะตรวจสอบว่ามีไฟล์อยู่โดยไม่ใช้คำสั่ง try ได้อย่างไร

ในปี 2559 นี้ยังคงเป็นวิธีที่ง่ายที่สุดในการตรวจสอบว่ามีทั้งไฟล์อยู่หรือไม่และเป็นไฟล์:

import os
os.path.isfile('./file.txt')    # Returns True if exists, else False

isfileจริงๆแล้วเป็นเพียงวิธีการช่วยเหลือที่ใช้ภายในos.statและstat.S_ISREG(mode)ภายใต้ นี่os.statเป็นวิธีการระดับล่างที่จะให้ข้อมูลรายละเอียดเกี่ยวกับไฟล์ไดเรกทอรีซ็อกเก็ตบัฟเฟอร์และอื่น ๆ ให้คุณ เพิ่มเติมเกี่ยวกับ os.stat ที่นี่

หมายเหตุ:อย่างไรก็ตามวิธีการนี้จะไม่ล็อคไฟล์ในทางใดทางหนึ่งและดังนั้นรหัสของคุณอาจเสี่ยงต่อ " เวลาตรวจสอบเวลาที่ใช้ " ( TOCTTOUข้อผิดพลาด )

ดังนั้นการยกข้อยกเว้นให้ถือว่าเป็นวิธีที่ยอมรับได้และ Pythonic เป็นวิธีการควบคุมการไหลในโปรแกรมของคุณ และควรพิจารณาจัดการไฟล์ที่หายไปด้วย IOErrors แทนที่จะเป็นifคำสั่ง ( เพียงคำแนะนำ )


9
import os.path

def isReadableFile(file_path, file_name):
    full_path = file_path + "/" + file_name
    try:
        if not os.path.exists(file_path):
            print "File path is invalid."
            return False
        elif not os.path.isfile(full_path):
            print "File does not exist."
            return False
        elif not os.access(full_path, os.R_OK):
            print "File cannot be read."
            return False
        else:
            print "File can be read."
            return True
    except IOError as ex:
        print "I/O error({0}): {1}".format(ex.errno, ex.strerror)
    except Error as ex:
        print "Error({0}): {1}".format(ex.errno, ex.strerror)
    return False
#------------------------------------------------------

path = "/usr/khaled/documents/puzzles"
fileName = "puzzle_1.txt"

isReadableFile(path, fileName)

@ j6m8 ใช่isReadableFile(path,fileName)จะกลับมาTrueถ้าไฟล์สามารถเข้าถึงได้และสามารถอ่านได้โดยกระบวนการ \ program \ thread
Khaled.K
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.