Câu trả lời:
Nếu lý do bạn đang kiểm tra là để bạn có thể làm điều gì đó như thế if file_exists: open_it()
, thì an toàn hơn là sử dụng try
xung quanh nỗ lực mở nó. Kiểm tra và sau đó mở có nguy cơ tệp bị xóa hoặc di chuyển hoặc một cái gì đó giữa khi bạn kiểm tra và khi bạn cố gắng mở nó.
Nếu bạn không định mở tệp ngay lập tức, bạn có thể sử dụng os.path.isfile
Trả về
True
nếu đường dẫn là một tệp thông thường hiện có. Điều này tuân theo các liên kết tượng trưng, vì vậy cả islink () và isfile () đều có thể đúng với cùng một đường dẫn.
import os.path
os.path.isfile(fname)
nếu bạn cần chắc chắn đó là một tập tin.
Bắt đầu với Python 3.4, pathlib
mô-đun cung cấp một cách tiếp cận hướng đối tượng (được nhập pathlib2
vào trong Python 2.7):
from pathlib import Path
my_file = Path("/path/to/file")
if my_file.is_file():
# file exists
Để kiểm tra một thư mục, hãy làm:
if my_file.is_dir():
# directory exists
Để kiểm tra xem một Path
đối tượng có tồn tại độc lập với việc đó là tệp hoặc thư mục hay không, hãy sử dụng exists()
:
if my_file.exists():
# path exists
Bạn cũng có thể sử dụng resolve(strict=True)
trong một try
khối:
try:
my_abs_path = my_file.resolve(strict=True)
except FileNotFoundError:
# doesn't exist
else:
# exists
FileNotFoundError
đã được giới thiệu trong Python 3. Nếu bạn cũng cần hỗ trợ Python 2.7 cũng như Python 3, bạn có thể sử dụng IOError
thay thế ( FileNotFoundError
lớp con nào) stackoverflow.com/a/21368457/1960959
open('file', 'r+')
) và sau đó tìm kiếm đến cùng.
Bạn có os.path.exists
chức năng:
import os.path
os.path.exists(file_path)
Điều này trả về True
cho cả tệp và thư mục nhưng thay vào đó bạn có thể sử dụng
os.path.isfile(file_path)
để kiểm tra nếu đó là một tập tin cụ thể. Nó theo symlink.
Không giống như isfile()
, exists()
sẽ trở lại True
cho các thư mục. Vì vậy, tùy thuộc vào việc bạn chỉ muốn các tệp đơn giản hoặc các thư mục, bạn sẽ sử dụng isfile()
hoặc exists()
. Đây là một số đầu ra REPL đơn giản:
>>> 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
Sử dụng os.path.isfile()
với 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")
os.access()
sẽ trả về false.
import os
, bạn không cần phải làm import os.path
lại vì nó đã là một phần của os
. Bạn chỉ cần nhập os.path
nếu bạn chỉ sử dụng các hàm từ os.path
và không phải từ os
chính nó, để nhập một thứ nhỏ hơn, nhưng khi bạn sử dụng os.access
vàos.R_OK
, không cần nhập lần thứ hai.
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
Mặc dù hầu hết mọi cách có thể đã được liệt kê trong (ít nhất một trong số) các câu trả lời hiện có (ví dụ: cụ thể Python 3,4 đã được thêm vào), tôi sẽ cố gắng nhóm mọi thứ lại với nhau.
Lưu ý : mọi đoạn mã thư viện chuẩn Python mà tôi sắp đăng, thuộc phiên bản 3.5.3 .
Báo cáo vấn đề :
Giải pháp có thể :
[Python 3]: os.path. tồn tại ( đường ) (cũng kiểm tra các thành viên chức năng khác trong gia đình như os.path.isfile
, os.path.isdir
, os.path.lexists
cho hành vi hơi khác nhau)
os.path.exists(path)
Trả về
True
nếu đường dẫn đề cập đến một đường dẫn hiện có hoặc một mô tả tệp mở. Trả vềFalse
cho các liên kết tượng trưng bị hỏng. Trên một số nền tảng, chức năng này có thể trở lạiFalse
nếu quyền không được cấp để thực thi os.stat () trên tệp được yêu cầu, ngay cả khi đường dẫn thực sự tồn tại.
Tất cả đều tốt, nhưng nếu theo cây nhập khẩu:
os.path
- posixpath.py ( ntpath.py )
genericpath.py , dòng ~ # 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
nó chỉ là một khối thử / ngoại trừ xung quanh [Python 3]: os. stat ( đường dẫn, *, dir_fd = Không có, follow_symlinks = True ) . Vì vậy, mã của bạn là thử / ngoại trừ miễn phí, nhưng thấp hơn trong framestack có (ít nhất) một khối như vậy. Điều này cũng áp dụng cho các chức năng khác ( bao gồm os.path.isfile
).
1.1. [Python 3]: Đường dẫn. is_file ()
Dưới mui xe, nó thực hiện chính xác điều tương tự ( pathlib.py , dòng ~ # 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
[Python 3]: Với Trình quản lý bối cảnh câu lệnh . Hoặc:
Tạo một cái:
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 ...)
Và cách sử dụng của nó - Tôi sẽ sao chép os.path.isfile
hành vi (lưu ý rằng đây chỉ là để thể hiện mục đích, không cố gắng viết mã như vậy cho sản xuất ):
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
Sử dụng [Python 3]: bối cảnh. triệt tiêu ( * ngoại lệ ) - được thiết kế đặc biệt để loại bỏ có chọn lọc các ngoại lệ
Tuy nhiên, họ dường như wrappers qua thử / trừ / khác / cuối cùng khối, như [Python 3]: Các với tuyên bố nêu rõ:
Điều này cho phép thử chung ... ngoại trừ ... cuối cùng các mẫu sử dụng được gói gọn để sử dụng lại thuận tiện.
Các chức năng truyền tải hệ thống tệp (và tìm kiếm kết quả cho (các) mục phù hợp)
[Python 3]: os. listdir ( path = '.' ) (hoặc [Python 3]: os. scandir ( path = '.' ) trên Python v 3.5 +, backport: [PyPI]: scandir )
Dưới mui xe, cả hai sử dụng:
thông qua [GitHub]: python / cpython - (master) cpython / Modules / posixmodule.c
Sử dụng scandir () thay cho listdir () có thể làm tăng đáng kể hiệu năng của mã cũng cần thông tin thuộc tính loại tệp hoặc thuộc tính tệp, vì các đối tượng os.DirEntry lộ thông tin này nếu hệ điều hành cung cấp nó khi quét thư mục. Tất cả các phương thức os.DirEntry có thể thực hiện một cuộc gọi hệ thống, nhưng is_dir () và is_file () thường chỉ yêu cầu một cuộc gọi hệ thống cho các liên kết tượng trưng; os.DirEntry.stat () luôn yêu cầu một cuộc gọi hệ thống trên Unix nhưng chỉ yêu cầu một liên kết tượng trưng trên Windows.
os.listdir
( os.scandir
khi có sẵn)glob.glob
:)
os.listdir
Vì các lần lặp này qua các thư mục, (trong hầu hết các trường hợp), chúng không hiệu quả cho vấn đề của chúng tôi (có những trường hợp ngoại lệ, như bing toàn cầu không được ký tự đại diện - như @ShadowRanger chỉ ra), vì vậy tôi sẽ không nhấn mạnh vào chúng. Chưa kể rằng trong một số trường hợp, xử lý tên tệp có thể được yêu cầu.
[Python 3]: os. truy cập ( đường dẫn, chế độ, *, dir_fd = Không có, có hiệu lực = Sai, follow_symlinks = Đúng ) có hành vi gần với os.path.exists
(thực ra nó rộng hơn, chủ yếu là do đối số thứ 2 )
... kiểm tra xem người dùng gọi có quyền truy cập được chỉ định vào đường dẫn hay không . Chế độ nên là F_OK để kiểm tra sự tồn tại của đường dẫn ...
os.access("/tmp", os.F_OK)
Kể từ khi tôi còn làm việc trong C , tôi sử dụng phương pháp này cũng bởi vì dưới mui xe, nó gọi mẹ đẻ API s (một lần nữa, thông qua "$ {} PYTHON_SRC_DIR /Modules/posixmodule.c" ), nhưng nó cũng mở ra một cánh cửa để có thể sử dụng lỗi và nó không phải là ic Python như các biến thể khác. Vì vậy, như @AaronHall đã chỉ ra một cách đúng đắn, đừng sử dụng nó trừ khi bạn biết bạn đang làm gì:
Lưu ý : cũng có thể gọi API gốc thông qua [Python 3]: ctypes - Thư viện hàm ngoại cho Python , nhưng trong hầu hết các trường hợp, nó phức tạp hơn.
( Win cụ thể): Kể từ khi vcruntime * ( msvcr * ) .dll xuất khẩu một [MS.Docs]: _access, _waccess gia đình chức năng là tốt, đây là một ví dụ:
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
Ghi chú :
os.F_OK
trong cuộc gọi, nhưng đó chỉ là sự rõ ràng (giá trị của nó là 0 )
Bản sao Lnx ( Ubtu (16 x64) ) cũng vậy:
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
Ghi chú :
Thay vào đó , đường dẫn của mã hóa libc ( "/lib/x86_64-linux-gnu/libc.so.6" ) có thể (và rất có thể, sẽ) khác nhau giữa các hệ thống, Không ai (hoặc chuỗi trống) có thể được chuyển đến hàm tạo CDLL ( ctypes.CDLL(None).access(b"/tmp", os.F_OK)
). Theo [man7]: DLOPEN (3) :
Nếu tên tệp là NULL, thì xử lý trả về là dành cho chương trình chính. Khi được trao cho dlsym (), tay cầm này gây ra tìm kiếm biểu tượng trong chương trình chính, theo sau là tất cả các đối tượng chia sẻ được tải khi khởi động chương trình và sau đó tất cả các đối tượng chia sẻ được tải bởi dlopen () với cờ RTLD_GLOBAL .
__declspec(dllexport)
(tại sao trên trái đất, người bình thường sẽ làm điều đó?), chương trình chính có thể tải nhưng khá nhiều không sử dụng đượcCài đặt một số mô-đun của bên thứ ba với khả năng hệ thống tập tin
Nhiều khả năng, sẽ dựa vào một trong những cách trên (có thể với các tùy chỉnh nhỏ).
Một ví dụ sẽ là (một lần nữa, Win cụ thể) [GitHub]: mhammond / pywin32 - Phần mở rộng Python cho Windows (pywin32) , là một trình bao bọc Python trên WINAPI .
Nhưng, vì đây giống như một cách giải quyết hơn, tôi dừng lại ở đây.
Một cách giải quyết khác (khập khiễng) ( gainarie ) là (như tôi muốn gọi nó), cách tiếp cận sysadmin : sử dụng Python như một trình bao bọc để thực thi các lệnh shell
Giành chiến thắng :
(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
Nix ( 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
Dòng dưới cùng :
Lưu ý cuối cùng :
glob.iglob
(và glob.glob
cũng vậy) dựa trênos.scandir
, vì vậy bây giờ nó lười biếng; để có được lần truy cập đầu tiên trong thư mục gồm 10 triệu tệp, bạn chỉ quét cho đến khi bạn đạt được lần truy cập đầu tiên. Và ngay cả trước 3.6, nếu bạn sử dụng glob
các phương thức không có bất kỳ ký tự đại diện nào, chức năng này rất thông minh: Nó biết bạn chỉ có thể có một lần truy cập, do đó, nó đơn giản hóa việc tạo hình thành chỉ os.path.isdir
hoặcos.path.lexists
(tùy thuộc vào việc đường dẫn kết thúc /
).
os.path.isdir
hoặc os.path.lexist
vì đó là một chuỗi các lệnh gọi và chuỗi hàm cấp Python hoạt động trước khi nó quyết định đường dẫn hiệu quả là khả thi, nhưng không có cuộc gọi hệ thống hoặc I / O bổ sung nào hoạt động, đó là các lệnh có cường độ chậm hơn).
Đây là cách đơn giản nhất để kiểm tra nếu một tập tin tồn tại. Chỉ vì tệp tồn tại khi bạn kiểm tra không đảm bảo rằng nó sẽ ở đó khi bạn cần mở nó.
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")
Python 3.4+ có mô-đun đường dẫn hướng đối tượng: pathlib . Sử dụng mô-đun mới này, bạn có thể kiểm tra xem một tệp có tồn tại như thế này không:
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
Bạn có thể (và thường nên) vẫn sử dụng một try/except
khối khi mở tệp:
try:
with p.open() as f:
# do awesome stuff
except OSError:
print('Well darn.')
Mô-đun pathlib có rất nhiều nội dung thú vị trong đó: tạo khối thuận tiện, kiểm tra chủ sở hữu tệp, tham gia đường dẫn dễ dàng hơn, v.v ... Thật đáng để kiểm tra. Nếu bạn đang dùng Python cũ (phiên bản 2.6 trở lên), bạn vẫn có thể cài đặt pathlib với pip:
# installs pathlib2 on older Python versions
# the original third-party module, pathlib, is no longer maintained.
pip install pathlib2
Sau đó nhập nó như sau:
# Older Python versions
import pathlib2 as pathlib
Thích tuyên bố thử. Nó được coi là phong cách tốt hơn và tránh các điều kiện chủng tộc.
Đừng tin lời tôi. Có rất nhiều hỗ trợ cho lý thuyết này. Đây là một cặp vợ chồng:
try...except
không giúp phân giải rằng vấn đề anyway.
except:
mệnh đề sẽ làm cho một ngoại lệ phát sinh trong phần này của mã của bạn sẽ đưa ra một thông báo khó hiểu (lỗi thứ hai được đưa ra trong quá trình việc xử lý cái đầu tiên.)
Làm cách nào để kiểm tra xem một tệp có tồn tại hay không, sử dụng Python mà không sử dụng câu lệnh try?
Hiện có sẵn từ Python 3.4, nhập và khởi tạo một Path
đối tượng bằng tên tệp và kiểm tra is_file
phương thức (lưu ý rằng điều này trả về True cho các liên kết tượng trưng chỉ vào các tệp thông thường):
>>> from pathlib import Path
>>> Path('/').is_file()
False
>>> Path('/initrd.img').is_file()
True
>>> Path('/doesnotexist').is_file()
False
Nếu bạn đang dùng Python 2, bạn có thể nhập mô-đun pathlib từ pypi pathlib2
hoặc kiểm tra isfile
từ os.path
mô-đun:
>>> import os
>>> os.path.isfile('/')
False
>>> os.path.isfile('/initrd.img')
True
>>> os.path.isfile('/doesnotexist')
False
Bây giờ có lẽ là câu trả lời trực tiếp thực dụng tốt nhất ở đây, nhưng có khả năng xảy ra tình trạng chủng tộc (tùy thuộc vào những gì bạn đang cố gắng thực hiện) và thực tế là việc triển khai cơ bản sử dụng một try
, nhưng Python sử dụng try
ở mọi nơi trong quá trình thực hiện.
Bởi vì Python sử dụng try
ở mọi nơi, thực sự không có lý do gì để tránh việc triển khai sử dụng nó.
Nhưng phần còn lại của câu trả lời này cố gắng xem xét những cảnh báo này.
Có sẵn từ Python 3.4, sử dụng Path
đối tượng mới trong pathlib
. Lưu ý rằng điều đó .exists
không hoàn toàn đúng, bởi vì các thư mục không phải là tệp (ngoại trừ theo nghĩa unix rằng mọi thứ đều là tệp).
>>> from pathlib import Path
>>> root = Path('/')
>>> root.exists()
True
Vì vậy, chúng ta cần sử dụng is_file
:
>>> root.is_file()
False
Đây là sự giúp đỡ về is_file
:
is_file(self)
Whether this path is a regular file (also True for symlinks pointing
to regular files).
Vì vậy, hãy lấy một tệp mà chúng ta biết là một tệp:
>>> import tempfile
>>> file = tempfile.NamedTemporaryFile()
>>> filepathobj = Path(file.name)
>>> filepathobj.is_file()
True
>>> filepathobj.exists()
True
Theo mặc định, NamedTemporaryFile
xóa tệp khi đóng (và sẽ tự động đóng khi không còn tham chiếu nào nữa).
>>> del file
>>> filepathobj.exists()
False
>>> filepathobj.is_file()
False
Tuy nhiên, nếu bạn đi sâu vào triển khai , bạn sẽ thấy điều đó is_file
sử dụng 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
Chúng tôi thích try
bởi vì nó tránh điều kiện chủng tộc. Với try
, bạn chỉ cần cố gắng đọc tệp của mình, hy vọng nó sẽ ở đó và nếu không, bạn sẽ bắt ngoại lệ và thực hiện bất kỳ hành vi dự phòng nào có ý nghĩa.
Nếu bạn muốn kiểm tra xem một tệp có tồn tại trước khi bạn cố đọc nó không, và bạn có thể đang xóa nó và sau đó bạn có thể đang sử dụng nhiều luồng hoặc quy trình, hoặc một chương trình khác biết về tệp đó và có thể xóa nó - bạn có nguy cơ một điều kiện cuộc đua nếu bạn kiểm tra nó tồn tại, bởi vì sau đó bạn đang chạy đua để mở nó trước điều kiện của nó của nó (sự tồn tại của nó) thay đổi.
Điều kiện cuộc đua rất khó để gỡ lỗi vì có một cửa sổ rất nhỏ trong đó chúng có thể khiến chương trình của bạn bị lỗi.
Nhưng nếu đây là động lực của bạn, bạn có thể nhận được giá trị của một try
tuyên bố bằng cách sử dụng trình suppress
quản lý bối cảnh.
suppress
Python 3.4 cung cấp cho chúng ta trình suppress
quản lý bối cảnh (trước đây là trình ignore
quản lý bối cảnh), thực hiện chính xác về mặt ngữ nghĩa trong cùng một số dòng, trong khi (ít nhất là bề ngoài) đáp ứng yêu cầu ban đầu để tránh một try
tuyên bố:
from contextlib import suppress
from pathlib import Path
Sử dụng:
>>> with suppress(OSError), Path('doesnotexist').open() as f:
... for line in f:
... print(line)
...
>>>
>>> with suppress(OSError):
... Path('doesnotexist').unlink()
...
>>>
Đối với Pythons trước đó, bạn có thể tự lăn suppress
, nhưng không có try
ý nghĩa sẽ dài dòng hơn so với. Tôi tin rằng đây thực sự là câu trả lời duy nhất không sử dụng try
ở bất kỳ cấp độ nào trong Python có thể được áp dụng cho Python 3,4 vì nó sử dụng trình quản lý bối cảnh:
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)
Có lẽ dễ dàng hơn với một thử:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
đồng vị
import os
os.path.isfile(path)
từ các tài liệu :
os.path.isfile(path)
Trả về True nếu đường dẫn là một tệp thông thường hiện có. Điều này tuân theo các liên kết tượng trưng, vì vậy cả hai
islink()
vàisfile()
có thể đúng cho cùng một đường dẫn.
Nhưng nếu bạn kiểm tra nguồn của hàm này, bạn sẽ thấy nó thực sự sử dụng câu lệnh thử:
# 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
Tất cả những gì nó đang làm là sử dụng đường dẫn đã cho để xem liệu nó có thể lấy số liệu thống kê về nó hay không, bắt OSError
và sau đó kiểm tra xem đó có phải là tệp không nếu nó không đưa ra ngoại lệ.
Nếu bạn có ý định làm một cái gì đó với tệp, tôi sẽ đề nghị trực tiếp thử nó với một lần thử - ngoại trừ để tránh điều kiện cuộc đua:
try:
with open(path) as f:
f.read()
except OSError:
pass
os.access
Có sẵn cho Unix và Windows os.access
, nhưng để sử dụng, bạn phải truyền cờ và nó không phân biệt giữa các tệp và thư mục. Điều này được sử dụng nhiều hơn để kiểm tra xem người dùng thực sự có quyền truy cập trong môi trường đặc quyền nâng cao hay không:
import os
os.access(path, os.F_OK)
Nó cũng bị các vấn đề điều kiện chủng tộc tương tự như isfile
. Từ các tài liệu :
Lưu ý: Sử dụng access () để kiểm tra xem người dùng có được phép mở tệp hay không trước khi thực sự sử dụng open () tạo lỗ hổng bảo mật, vì người dùng có thể khai thác khoảng thời gian ngắn giữa kiểm tra và mở tệp để thao tác. Nên sử dụng các kỹ thuật EAFP. Ví dụ:
if os.access("myfile", os.R_OK): with open("myfile") as fp: return fp.read() return "some default data"
được viết tốt hơn là:
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()
Tránh sử dụng os.access
. Đây là một hàm cấp thấp có nhiều cơ hội hơn cho lỗi người dùng so với các đối tượng và hàm cấp cao hơn được thảo luận ở trên.
Một câu trả lời khác nói về điều này os.access
:
Cá nhân, tôi thích cái này vì dưới mui xe, nó gọi API gốc (thông qua "$ {PYTHON_SRC_DIR} /Modules/poseixmodule.c"), nhưng nó cũng mở ra một cổng cho các lỗi người dùng có thể xảy ra và nó không phải là Pythonic như các biến thể khác :
Câu trả lời này cho biết họ thích một phương pháp không có lỗi Pythonic, không có lỗi. Dường như khuyến khích người dùng sử dụng API cấp thấp mà không hiểu chúng.
Nó cũng tạo ra một trình quản lý bối cảnh, bằng cách quay lại vô điều kiện True
, cho phép tất cả các Ngoại lệ (bao gồm KeyboardInterrupt
và SystemExit
!) Vượt qua một cách im lặng, đó là một cách tốt để che giấu các lỗi.
Điều này dường như để khuyến khích người dùng áp dụng các thực hành kém.
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!"
Nhập os
giúp dễ dàng điều hướng và thực hiện các hành động tiêu chuẩn với hệ điều hành của bạn.
Để tham khảo cũng xem Làm thế nào để kiểm tra xem một tệp có tồn tại bằng Python không?
Nếu bạn cần hoạt động cấp cao, sử dụng shutil
.
os.path.exists
trả về true cho những thứ không phải là tập tin, chẳng hạn như thư mục. Điều này cho kết quả dương tính giả. Xem các câu trả lời khác mà đề nghị os.path.isfile
.
Kiểm tra các tệp và thư mục với os.path.isfile()
, os.path.isdir()
vàos.path.exists()
Giả sử rằng "đường dẫn" là một đường dẫn hợp lệ, bảng này hiển thị những gì được trả về bởi mỗi chức năng cho các tệp và thư mục:
Bạn cũng có thể kiểm tra xem một tệp có phải là một loại tệp nhất định bằng cách sử dụng os.path.splitext()
phần mở rộng không (nếu bạn chưa biết)
>>> 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
Trong năm 2016, cách tốt nhất vẫn là sử dụng os.path.isfile
:
>>> os.path.isfile('/path/to/some/file.txt')
Hoặc trong Python 3 bạn có thể sử dụng pathlib
:
import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
...
pathlib
là giải pháp OOP của python cho các đường dẫn. Bạn có thể làm nhiều hơn với nó. Nếu bạn chỉ cần kiểm tra sự tồn tại, lợi thế không quá lớn.
Dường như không có sự khác biệt về ý nghĩa chức năng giữa thử / ngoại trừ và isfile()
vì vậy bạn nên sử dụng cái nào có ý nghĩa.
Nếu bạn muốn đọc một tập tin, nếu nó tồn tại, hãy làm
try:
f = open(filepath)
except IOError:
print 'Oh dear.'
Nhưng nếu bạn chỉ muốn đổi tên một tệp nếu nó tồn tại và do đó không cần phải mở nó, hãy làm
if os.path.isfile(filepath):
os.rename(filepath, filepath + '.old')
Nếu bạn muốn ghi vào một tập tin, nếu nó không tồn tại, hãy làm
# 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'
Nếu bạn cần khóa tập tin, đó là một vấn đề khác.
os.path.exists
trả về true cho những thứ không phải là tập tin, chẳng hạn như thư mục. Điều này cho kết quả dương tính giả. Xem các câu trả lời khác mà đề nghị os.path.isfile
.
filepath
đúng thời gian và BAM , bạn ghi đè lên tệp đích. Bạn nên làm open(filepath, 'wx')
trong một try...except
khối để tránh vấn đề.
OSError
nếu filepath + '.old'
đã tồn tại: "Trên Windows, nếu dst đã tồn tại, OSError sẽ được nâng lên ngay cả khi đó là một tệp, có thể không có cách nào để thực hiện đổi tên nguyên tử khi dst đặt tên cho một tập tin hiện có. "
os.replace
thực hiện thay thế im lặng tệp đích (nó giống hệt với os.rename
hành vi Linux của nó) (nó chỉ bị lỗi nếu tên đích tồn tại và là một thư mục). Vì vậy, bạn bị mắc kẹt trên 2.x, nhưng người dùng Py3 đã có một lựa chọn tốt trong vài năm nay.
rename
ví dụ: Nó vẫn nên được thực hiện với try
/ except
. os.rename
(hoặc os.replace
trên Python hiện đại) là nguyên tử; làm cho nó kiểm tra sau đó đổi tên giới thiệu một cuộc đua không cần thiết và các cuộc gọi hệ thống bổ sung. Chỉ cần làmtry: os.replace(filepath, filepath + '.old') except OSError: pass
Bạn có thể thử điều này (an toàn hơn):
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))
Thông số sẽ là:
([Errno 2] Không có tệp hoặc thư mục như vậy: 'anything.txt')
Sau đó, tùy thuộc vào kết quả, chương trình của bạn có thể tiếp tục chạy từ đó hoặc bạn có thể mã để dừng nó nếu bạn muốn.
try
Mặc dù tôi luôn khuyên bạn nên sử dụng try
và except
báo cáo, đây là một vài khả năng cho bạn (sở thích cá nhân của tôi đang sử dụng os.access
):
Hãy thử mở tệp:
Mở tệp sẽ luôn xác minh sự tồn tại của tệp. Bạn có thể tạo một chức năng giống như vậy:
def File_Existence(filepath):
f = open(filepath)
return True
Nếu nó sai, nó sẽ dừng thực thi với IOError hoặc OSError chưa được xử lý trong các phiên bản sau của Python. Để bắt ngoại lệ, bạn phải sử dụng mệnh đề thử ngoại trừ. Tất nhiên, bạn luôn có thể sử dụng một try
tuyên bố except` như vậy (nhờ hsandt
đã làm cho tôi nghĩ rằng):
def File_Existence(filepath):
try:
f = open(filepath)
except IOError, OSError: # Note OSError is for later versions of Python
return False
return True
Sử dụng os.path.exists(path)
:
Điều này sẽ kiểm tra sự tồn tại của những gì bạn chỉ định. Tuy nhiên, nó kiểm tra các tập tin và thư mục vì vậy hãy cẩn thận về cách bạn sử dụng nó.
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
Sử dụng os.access(path, mode)
:
Điều này sẽ kiểm tra xem bạn có quyền truy cập vào tập tin. Nó sẽ kiểm tra quyền. Dựa trên tài liệu os.py, gõ vào os.F_OK
, nó sẽ kiểm tra sự tồn tại của đường dẫn. Tuy nhiên, sử dụng điều này sẽ tạo ra một lỗ hổng bảo mật, vì ai đó có thể tấn công tệp của bạn trong khoảng thời gian giữa việc kiểm tra quyền và mở tệp. Thay vào đó, bạn nên trực tiếp mở tệp thay vì kiểm tra quyền của nó. ( EAFP vs LBYP ). Nếu bạn sẽ không mở tệp sau đó và chỉ kiểm tra sự tồn tại của nó, thì bạn có thể sử dụng tệp này.
Dù sao, ở đây:
>>> import os
>>> os.access("/is/a/file.txt", os.F_OK)
True
Tôi cũng nên đề cập rằng có hai cách mà bạn sẽ không thể xác minh sự tồn tại của một tệp. Vấn đề sẽ là permission denied
hoặc no such file or directory
. Nếu bạn bắt được IOError
, hãy đặt IOError as e
(như tùy chọn đầu tiên của tôi), sau đó nhập print(e.args)
để bạn có thể xác định vấn đề của mình. Tôi hy vọng nó sẽ giúp! :)
Ngày: 2017-12-04
Mọi giải pháp có thể đã được liệt kê trong các câu trả lời khác.
Một cách trực quan và có thể tranh luận để kiểm tra xem một tập tin có tồn tại hay không là như sau:
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')
Tôi đã thực hiện một chiếc áo choàng đầy đủ để bạn tham khảo:
#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']}
Nếu tệp để mở, bạn có thể sử dụng một trong các kỹ thuật sau:
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!')
CẬP NHẬT
Chỉ để tránh nhầm lẫn và dựa trên các câu trả lời tôi nhận được, câu trả lời hiện tại tìm thấy một tệp hoặc một thư mục có tên đã cho.
os.path.exists
trả về true cho những thứ không phải là tập tin, chẳng hạn như thư mục. Điều này cho kết quả dương tính giả. Xem các câu trả lời khác mà đề nghị os.path.isfile
.
if os.path.isfile(path_to_file):
try:
open(path_to_file)
pass
except IOError as e:
print "Unable to open file"
Tăng các ngoại lệ được coi là một cách tiếp cận có thể chấp nhận và Pythonic, để kiểm soát dòng chảy trong chương trình của bạn. Xem xét xử lý các tệp bị thiếu với IOErrors. Trong tình huống này, một ngoại lệ IOError sẽ được nêu ra nếu tệp tồn tại nhưng người dùng không có quyền đọc.
Bạn có thể viết đề xuất của Brian mà không cần try:
.
from contextlib import suppress
with suppress(IOError), open('filename'):
process()
suppress
là một phần của Python 3.4. Trong các bản phát hành cũ hơn, bạn có thể nhanh chóng viết ra sự kìm nén của chính mình:
from contextlib import contextmanager
@contextmanager
def suppress(*exceptions):
try:
yield
except exceptions:
pass
Tôi là tác giả của một gói đã tồn tại khoảng 10 năm và nó có chức năng giải quyết trực tiếp câu hỏi này. Về cơ bản, nếu bạn đang sử dụng hệ thống không phải Windows, nó sẽ sử dụng Popen
để truy cập find
. Tuy nhiên, nếu bạn đang ở trên Windows, nó sẽ sao chép find
với một walker hệ thống tập tin hiệu quả.
Bản thân mã không sử dụng một try
khối khối trừ khi xác định hệ điều hành và do đó hướng bạn đến kiểu "Unix" find
hoặc buillt tay find
. Các thử nghiệm về thời gian cho thấy rằng việc try
xác định HĐH nhanh hơn, vì vậy tôi đã sử dụng một hệ thống ở đó (nhưng không ở đâu khác).
>>> import pox
>>> pox.find('*python*', type='file', root=pox.homedir(), recurse=False)
['/Users/mmckerns/.python']
Và tài liệu
>>> 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']
>>>
Việc triển khai, nếu bạn quan tâm, sẽ ở đây: https://github.com/uqfoundation/pox/blob/89f90fb308f285ca7a62eabe2c38acb87e89dad9/pox/shutils.py#L190
Bạn có thể làm theo ba cách sau:
Lưu ý1: Chỉ
os.path.isfile
được sử dụng cho các tệp
import os.path
os.path.isfile(filename) # True if file exists
os.path.isfile(dirname) # False if directory exists
Note2: Được
os.path.exists
sử dụng cho cả tệp và thư mục
import os.path
os.path.exists(filename) # True if file exists
os.path.exists(dirname) #True if directory exists
Các
pathlib.Path
phương pháp (bao gồm trong Python 3+, có thể cài đặt với pip cho Python 2)
from pathlib import Path
Path(filename).exists()
Thêm một biến thể nhỏ nữa mà không được phản ánh chính xác trong các câu trả lời khác.
Điều này sẽ xử lý các trường hợp file_path
là None
chuỗi hoặc rỗng.
def file_exists(file_path):
if not file_path:
return False
elif not os.path.isfile(file_path):
return False
else:
return True
Thêm một biến thể dựa trên đề xuất từ Shahbaz
def file_exists(file_path):
if not file_path:
return False
else:
return os.path.isfile(file_path)
Thêm một biến thể dựa trên đề xuất từ Peter Wood
def file_exists(file_path):
return file_path and os.path.isfile(file_path):
if (x) return true; else return false;
thực sự chỉ return x
. Bốn dòng cuối cùng của bạn có thể trở thành return os.path.isfile(file_path)
. Trong khi chúng ta đang ở đó, toàn bộ chức năng có thể được đơn giản hóa như return file_path and os.path.isfile(file_path)
.
return x
trong trường hợp if (x)
. Python sẽ xem xét một chuỗi rỗng Sai trong trường hợp chúng ta sẽ trả về một chuỗi rỗng thay vì bool. Mục đích của chức năng này là luôn trả về bool.
x
là os.path.isfile(..)
vì vậy nó đã bool.
os.path.isfile(None)
đưa ra một ngoại lệ đó là lý do tại sao tôi thêm kiểm tra if. Tôi có thể chỉ cần bọc nó trong một lần thử / ngoại trừ thay vào đó nhưng tôi cảm thấy nó rõ ràng hơn theo cách này.
return file_path and os.path.isfile(file_path)
Đây là lệnh Python 1 dòng cho môi trường dòng lệnh Linux. Tôi thấy điều này RẤT TUYỆT VỜI vì tôi không phải là một anh chàng Bash nóng bỏng như vậy.
python -c "import os.path; print os.path.isfile('/path_to/file.xxx')"
Tôi hy vọng điều này là hữu ích.
[ -f "${file}" ] && echo "file found" || echo "file not found"
(giống như if [ ... ]; then ...; else ...; fi
).
Bạn có thể sử dụng thư viện "HĐH" của Python:
>>> import os
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.txt")
True
>>> os.path.exists("C:\\Users\\####\\Desktop\\test.tx")
False
os.path.exists
trả về true cho những thứ không phải là tập tin, chẳng hạn như thư mục. Điều này cho kết quả dương tính giả. Xem các câu trả lời khác mà đề nghị os.path.isfile
.
exists
vẫn ổn. Nếu mục tiêu là xác định liệu có an toàn để mở một tệp có lẽ là hiện tại hay không, thì lời chỉ trích là hợp lý và tồn tại là không đủ chính xác. Đáng buồn thay, OP không chỉ định mục tiêu mong muốn (và có lẽ sẽ không làm như vậy nữa).
Làm cách nào để kiểm tra xem một tệp có tồn tại mà không sử dụng câu lệnh try không?
Trong năm 2016, đây vẫn là cách dễ nhất để kiểm tra xem cả hai tệp có tồn tại hay không và đó có phải là tệp không:
import os
os.path.isfile('./file.txt') # Returns True if exists, else False
isfile
thực sự chỉ là một phương thức trợ giúp sử dụng nội bộ os.stat
và stat.S_ISREG(mode)
bên dưới. Đây os.stat
là một phương pháp cấp thấp hơn sẽ cung cấp cho bạn thông tin chi tiết về các tệp, thư mục, ổ cắm, bộ đệm, v.v. Tìm hiểu thêm về os.stat tại đây
Lưu ý: Tuy nhiên, cách tiếp cận này sẽ không khóa tệp theo bất kỳ cách nào và do đó mã của bạn có thể trở nên dễ bị tổn thương do lỗi " thời gian kiểm tra đến thời gian sử dụng " ( TOCTTOU ).
Vì vậy, nâng cao các ngoại lệ được coi là một cách tiếp cận có thể chấp nhận và Pythonic, để kiểm soát dòng chảy trong chương trình của bạn. Và người ta nên xem xét xử lý các tệp bị thiếu bằng IOErrors, thay vì các if
câu lệnh ( chỉ là một lời khuyên ).
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)
isReadableFile(path,fileName)
sẽ trở lại True
nếu tệp có thể truy cập và có thể đọc được theo quy trình \ chương trình \ thread