Kiểm tra xem một đường dẫn có hợp lệ trong Python mà không cần tạo tệp tại đích của đường dẫn hay không


98

Tôi có một đường dẫn (bao gồm cả thư mục và tên tệp).
Tôi cần kiểm tra xem tên tệp có hợp lệ không, ví dụ: nếu hệ thống tệp có cho phép tôi tạo tệp với tên như vậy không.
Tên tệp có một số ký tự unicode trong đó.

Thật an toàn nếu giả sử phân đoạn thư mục của đường dẫn là hợp lệ và có thể truy cập được ( tôi đang cố gắng làm cho câu hỏi có thể áp dụng một cách tang lễ hơn và dường như tôi đã đi quá xa ).

Tôi rất không muốn phải trốn tránh bất cứ điều gì trừ khi tôi phải làm vậy.

Tôi muốn đăng một số ký tự ví dụ mà tôi đang xử lý, nhưng rõ ràng chúng bị hệ thống trao đổi ngăn xếp tự động xóa. Dù sao, tôi muốn giữ các thực thể unicode tiêu chuẩn như övà chỉ thoát những thứ không hợp lệ trong tên tệp.


Đây là sản phẩm. Có thể (hoặc không) đã có một tệp ở đích của đường dẫn. Tôi cần giữ tệp đó nếu nó tồn tại và không tạo tệp nếu không có.

Về cơ bản, tôi muốn kiểm tra xem mình có thể ghi vào một đường dẫn mà không thực sự mở đường dẫn để ghi (và việc tạo tệp tự động / chặn tệp thường đòi hỏi).

Như vậy:

try:
    open(filename, 'w')
except OSError:
    # handle error here

từ đây

Không được chấp nhận, vì nó sẽ ghi đè lên tệp hiện có mà tôi không muốn chạm vào (nếu nó ở đó) hoặc tạo tệp đã nói nếu nó không có.

Tôi biết tôi có thể làm:

if not os.access(filePath, os.W_OK):
    try:
        open(filePath, 'w').close()
        os.unlink(filePath)
    except OSError:
        # handle error here

Nhưng điều đó sẽ tạo ra tệp tại filePath, mà sau đó tôi sẽ phải làm os.unlink.

Cuối cùng, có vẻ như nó dành 6 hoặc 7 dòng để làm điều gì đó đơn giản os.isvalidpath(filePath)hoặc tương tự.


Ngoài ra, tôi cần nó chạy trên (ít nhất) Windows và MacOS, vì vậy tôi muốn tránh những thứ dành riêng cho nền tảng.

``


Nếu bạn muốn kiểm tra xem đường dẫn có tồn tại hay không và bạn có thể ghi vào nó, thì chỉ cần tạo và xóa một số tệp khác. Đặt cho nó một tên duy nhất (hoặc duy nhất nếu bạn có thể), để tránh các vấn đề đa người dùng / đa luồng. Nếu không, bạn đang xem xét kiểm tra các hoán vị sẽ đưa bạn thẳng vào cuộc tranh luận cụ thể của hệ điều hành.
Tony Hopkinson

3
@Tony Hopkinson - Về cơ bản, tôi muốn kiểm tra xem liệu tôi có thể viết vào một đường dẫn mà không thực sự viết bất cứ thứ gì hay không .
Tên giả vào

Nếu bạn không có gì để ghi vào tệp, thì tại sao bạn cần biết liệu bạn có thể làm được không?
Karl Knechtel

@Karl Knechtel - Nếu tôi ghi vào nó và đã có một tệp ở đó, nó sẽ làm hỏng tệp hiện có.
Tên giả vào

2
@FakeName - Bạn sẽ luôn có một điều kiện đua phức tạp ở đây. Giữa việc kiểm tra xem tệp không tồn tại nhưng có thể được tạo, và sau đó tạo tệp, một số quy trình khác có thể tạo ra nó và bạn vẫn sẽ chặn tệp. Tất nhiên, nó phụ thuộc vào cách sử dụng của bạn cho dù đây là một vấn đề thực tế hay không ...
detly

Câu trả lời:


154

tl; dr

Gọi is_path_exists_or_creatable()hàm được xác định bên dưới.

Python 3. Đó chỉ là cách chúng tôi cuộn.

Câu chuyện về hai câu hỏi

Câu hỏi "Làm cách nào để kiểm tra tính hợp lệ của tên đường dẫn và đối với tên đường dẫn hợp lệ, sự tồn tại hoặc khả năng ghi của các đường dẫn đó?" rõ ràng là hai câu hỏi riêng biệt. Cả hai đều thú vị, và cả hai đều không nhận được câu trả lời thực sự thỏa đáng ở đây ... hoặc, tốt, bất cứ nơi nào mà tôi có thể grep.

Câu trả lời của vikki có lẽ gần nhất, nhưng có những nhược điểm đáng chú ý là:

  • Mở ( ... và sau đó không thể đóng ) các tệp xử lý một cách không cần thiết .
  • Không cần thiết phải ghi ( ... và sau đó không thể đóng hoặc xóa ) các tệp 0 byte đáng tin cậy .
  • Bỏ qua các lỗi dành riêng cho hệ điều hành, phân biệt giữa tên đường dẫn không hợp lệ không thể bỏ qua và các sự cố hệ thống tệp có thể bỏ qua. Không có gì đáng ngạc nhiên, điều này rất quan trọng trong Windows. ( Xem bên dưới. )
  • Bỏ qua các điều kiện chủng tộc do các quy trình bên ngoài đồng thời (lại) di chuyển các thư mục mẹ của tên đường dẫn cần kiểm tra. ( Xem bên dưới. )
  • Bỏ qua thời gian chờ kết nối do tên đường dẫn này nằm trên hệ thống tệp cũ, chậm hoặc tạm thời không thể truy cập được. Điều này có thể khiến các dịch vụ công khai trước các cuộc tấn công DoS -driven tiềm ẩn . ( Xem bên dưới. )

Chúng tôi sẽ sửa chữa tất cả những điều đó.

Câu hỏi # 0: Tính hợp lệ của Pathname lại là gì?

Trước khi ném bộ quần áo mỏng manh của chúng ta vào đống phân của con trăn vì đau đớn, có lẽ chúng ta nên định nghĩa "tính hợp lệ của tên đường dẫn" là gì. Điều gì xác định tính hợp lệ, chính xác?

Bởi "tính hợp lệ của tên đường dẫn", chúng tôi muốn nói đến tính đúng cú pháp của tên đường dẫn đối với hệ thống tệp gốc của hệ thống hiện tại - bất kể đường dẫn đó hay các thư mục mẹ của chúng có tồn tại thực tế hay không. Tên đường dẫn là chính xác về mặt cú pháp theo định nghĩa này nếu nó tuân thủ tất cả các yêu cầu cú pháp của hệ thống tệp gốc.

Theo "hệ thống tệp gốc", chúng tôi muốn nói:

  • Trên các hệ thống tương thích với POSIX, hệ thống tệp được gắn vào thư mục gốc ( /).
  • Trên Windows, hệ thống tệp được gắn vào %HOMEDRIVE%, ký tự ổ đĩa có hậu tố là dấu hai chấm chứa cài đặt Windows hiện tại (thường nhưng không nhất thiết C:).

Đến lượt mình, ý nghĩa của "tính đúng cú pháp" phụ thuộc vào loại hệ thống tệp gốc. Đối với ext4(và hầu hết nhưng không phải tất cả các hệ thống tệp tương thích với POSIX), tên đường dẫn là chính xác về mặt cú pháp nếu và chỉ khi tên đường dẫn đó:

  • Không chứa byte rỗng (tức là \x00trong Python). Đây là một yêu cầu khó đối với tất cả các hệ thống tệp tương thích với POSIX.
  • Không chứa các thành phần đường dẫn dài hơn 255 byte (ví dụ: 'a'*256trong Python). Một thành phần con đường là một chuỗi dài nhất của một tên đường dẫn không chứa /ký tự (ví dụ, bergtatt, ind, i, và fjeldkamrenetrong tên đường dẫn /bergtatt/ind/i/fjeldkamrene).

Tính đúng đắn về mặt cú pháp. Hệ thống tập tin gốc. Đó là nó.

Câu hỏi # 1: Bây giờ chúng ta sẽ thực hiện tính hợp lệ của tên đường dẫn như thế nào?

Xác thực tên đường dẫn trong Python đáng ngạc nhiên là không trực quan. Tôi đồng ý chắc chắn với Fake Name ở đây: os.pathgói chính thức nên cung cấp giải pháp ngoại vi cho việc này. Vì những lý do không xác định (và có thể là không thuyết phục), nó không. May mắn thay, việc gỡ bỏ giải pháp đặc biệt của riêng bạn không phải là điều khiến bạn khó chịu ...

OK, nó thực sự là như vậy. Nó có lông; thật khó chịu; nó có thể khó thở khi nó nhào lộn và cười khúc khích khi nó phát sáng. Nhưng bạn sẽ làm gì? Nuthin '.

Chúng ta sẽ sớm rơi xuống vực thẳm phóng xạ của mã cấp thấp. Nhưng trước hết hãy nói đến shop cao cấp. Tiêu chuẩn os.stat()và các os.lstat()hàm nêu ra các ngoại lệ sau khi chuyển tên đường dẫn không hợp lệ:

  • Đối với tên đường dẫn nằm trong các thư mục không tồn tại, các trường hợp của FileNotFoundError.
  • Đối với tên đường dẫn nằm trong các thư mục hiện có:
    • Trong Windows, các trường hợp WindowsErrorwinerrorthuộc tính là 123(tức là ERROR_INVALID_NAME).
    • Trong tất cả các hệ điều hành khác:
    • Đối với tên đường dẫn chứa byte rỗng (tức là, '\x00'), các trường hợp của TypeError.
    • Đối với tên đường dẫn chứa các thành phần đường dẫn dài hơn 255 byte, các trường hợp OSErrorerrcodethuộc tính là:
      • Dưới SunOS và họ hệ điều hành * BSD , errno.ERANGE. (Đây dường như là một lỗi cấp hệ điều hành, hay còn được gọi là "diễn giải có chọn lọc" của tiêu chuẩn POSIX.)
      • Trong tất cả các hệ điều hành khác errno.ENAMETOOLONG,.

Điều quan trọng, điều này ngụ ý rằng chỉ những tên đường dẫn nằm trong các thư mục hiện có mới có thể xác thực được. Các hàm os.stat()os.lstat()nâng cao các FileNotFoundErrorngoại lệ chung khi các tên đường dẫn được chuyển nằm trong các thư mục không tồn tại, bất kể các tên đường dẫn đó có hợp lệ hay không. Sự tồn tại của thư mục được ưu tiên hơn tính không hợp lệ của tên đường dẫn.

Điều này có nghĩa là các tên đường dẫn nằm trong các thư mục không tồn tại sẽ không hợp lệ? Có - trừ khi chúng tôi sửa đổi các tên đường dẫn đó để nằm trong các thư mục hiện có. Tuy nhiên, điều đó có khả thi một cách an toàn không? Việc sửa đổi tên đường dẫn có ngăn chúng ta xác thực tên đường dẫn ban đầu không?

Để trả lời câu hỏi này, hãy nhớ lại từ phía trên rằng các tên đường dẫn chính xác về mặt cú pháp trên ext4hệ thống tệp không chứa thành phần đường dẫn (A) chứa byte rỗng hoặc (B) có độ dài trên 255 byte. Do đó, ext4tên đường dẫn hợp lệ nếu và chỉ khi tất cả các thành phần đường dẫn trong tên đường dẫn đó hợp lệ. Điều này đúng với hầu hết các hệ thống tệp tin trong thế giới thực .

Cái nhìn sâu sắc đó có thực sự giúp chúng ta không? Đúng. Nó làm giảm vấn đề lớn hơn là xác thực tên đường dẫn đầy đủ trong một đường dẫn đã chuyển sang vấn đề nhỏ hơn là chỉ xác thực tất cả các thành phần đường dẫn trong tên đường dẫn đó. Mọi tên đường dẫn tùy ý đều có thể xác thực (bất kể tên đường dẫn đó có nằm trong thư mục hiện có hay không) theo cách đa nền tảng bằng cách thực hiện theo thuật toán sau:

  1. Chia tên đường dẫn đó thành các thành phần đường dẫn (ví dụ: tên đường dẫn /troldskog/faren/vildvào danh sách ['', 'troldskog', 'faren', 'vild']).
  2. Đối với mỗi thành phần như vậy:
    1. Nối tên đường dẫn của một thư mục được đảm bảo tồn tại với thành phần đó thành một tên đường dẫn tạm thời mới (ví dụ /troldskog:).
    2. Chuyển tên đường dẫn đó đến os.stat()hoặc os.lstat(). Nếu tên đường dẫn đó và do đó thành phần đó không hợp lệ, lệnh gọi này được đảm bảo đưa ra một ngoại lệ thể hiện kiểu không hợp lệ thay vì một FileNotFoundErrorngoại lệ chung chung . Tại sao? Bởi vì tên đường dẫn đó nằm trong một thư mục hiện có. (Logic tròn là vòng tròn.)

Có một thư mục được đảm bảo tồn tại? Có, nhưng thường chỉ có một: thư mục trên cùng của hệ thống tệp gốc (như đã định nghĩa ở trên).

Chuyển tên đường dẫn nằm trong bất kỳ thư mục nào khác (và do đó không được đảm bảo tồn tại) đến os.stat()hoặc os.lstat()mời các điều kiện cuộc đua, ngay cả khi thư mục đó đã được kiểm tra trước đó để tồn tại. Tại sao? Bởi vì các tiến trình bên ngoài không thể bị ngăn chặn đồng thời xóa thư mục đó sau khi kiểm tra đó đã được thực hiện nhưng trước khi tên đường dẫn đó được chuyển đến os.stat()hoặc os.lstat(). Giải phóng những con chó điên loạn trí óc!

Cũng có một lợi ích phụ đáng kể đối với cách tiếp cận trên: bảo mật. (Không phải là đẹp?) Cụ thể là:

Các ứng dụng trực diện xác nhận các tên đường dẫn tùy ý từ các nguồn không đáng tin cậy bằng cách chỉ cần chuyển các tên đường dẫn đó đến os.stat()hoặc os.lstat()dễ bị tấn công Từ chối Dịch vụ (DoS) và các trò tai quái khác. Người dùng độc hại có thể cố gắng xác thực nhiều lần các tên đường dẫn nằm trên các hệ thống tệp được biết là cũ hoặc chậm (ví dụ: chia sẻ NFS Samba); trong trường hợp đó, việc khai báo tên đường dẫn đến một cách mù quáng có thể cuối cùng sẽ không thành công với thời gian chờ kết nối hoặc tiêu tốn nhiều thời gian và tài nguyên hơn khả năng yếu ớt của bạn để chịu thất nghiệp.

Cách tiếp cận trên loại bỏ điều này bằng cách chỉ xác thực các thành phần đường dẫn của tên đường dẫn so với thư mục gốc của hệ thống tệp gốc. (Nếu thậm chí nó đã cũ, chậm hoặc không thể truy cập được, bạn đã gặp phải vấn đề lớn hơn xác thực tên đường dẫn.)

Mất đi? Tuyệt quá. Hãy bắt đầu nào. (Giả sử trong Python 3. Hãy xem "Mong manh mong manh cho 300, leycec là gì?")

import errno, os

# Sadly, Python fails to provide the following magic number for us.
ERROR_INVALID_NAME = 123
'''
Windows-specific error code indicating an invalid pathname.

See Also
----------
https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
    Official listing of all such codes.
'''

def is_pathname_valid(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname for the current OS;
    `False` otherwise.
    '''
    # If this pathname is either not a string or is but is empty, this pathname
    # is invalid.
    try:
        if not isinstance(pathname, str) or not pathname:
            return False

        # Strip this pathname's Windows-specific drive specifier (e.g., `C:\`)
        # if any. Since Windows prohibits path components from containing `:`
        # characters, failing to strip this `:`-suffixed prefix would
        # erroneously invalidate all valid absolute Windows pathnames.
        _, pathname = os.path.splitdrive(pathname)

        # Directory guaranteed to exist. If the current OS is Windows, this is
        # the drive to which Windows was installed (e.g., the "%HOMEDRIVE%"
        # environment variable); else, the typical root directory.
        root_dirname = os.environ.get('HOMEDRIVE', 'C:') \
            if sys.platform == 'win32' else os.path.sep
        assert os.path.isdir(root_dirname)   # ...Murphy and her ironclad Law

        # Append a path separator to this directory if needed.
        root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep

        # Test whether each path component split from this pathname is valid or
        # not, ignoring non-existent and non-readable path components.
        for pathname_part in pathname.split(os.path.sep):
            try:
                os.lstat(root_dirname + pathname_part)
            # If an OS-specific exception is raised, its error code
            # indicates whether this pathname is valid or not. Unless this
            # is the case, this exception implies an ignorable kernel or
            # filesystem complaint (e.g., path not found or inaccessible).
            #
            # Only the following exceptions indicate invalid pathnames:
            #
            # * Instances of the Windows-specific "WindowsError" class
            #   defining the "winerror" attribute whose value is
            #   "ERROR_INVALID_NAME". Under Windows, "winerror" is more
            #   fine-grained and hence useful than the generic "errno"
            #   attribute. When a too-long pathname is passed, for example,
            #   "errno" is "ENOENT" (i.e., no such file or directory) rather
            #   than "ENAMETOOLONG" (i.e., file name too long).
            # * Instances of the cross-platform "OSError" class defining the
            #   generic "errno" attribute whose value is either:
            #   * Under most POSIX-compatible OSes, "ENAMETOOLONG".
            #   * Under some edge-case OSes (e.g., SunOS, *BSD), "ERANGE".
            except OSError as exc:
                if hasattr(exc, 'winerror'):
                    if exc.winerror == ERROR_INVALID_NAME:
                        return False
                elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}:
                    return False
    # If a "TypeError" exception was raised, it almost certainly has the
    # error message "embedded NUL character" indicating an invalid pathname.
    except TypeError as exc:
        return False
    # If no exception was raised, all path components and hence this
    # pathname itself are valid. (Praise be to the curmudgeonly python.)
    else:
        return True
    # If any other exception was raised, this is an unrelated fatal issue
    # (e.g., a bug). Permit this exception to unwind the call stack.
    #
    # Did we mention this should be shipped with Python already?

Làm xong. Đừng nheo mắt trước mã đó. ( Nó cắn. )

Câu hỏi # 2: Sự tồn tại hoặc khả năng tạo ra tên đường dẫn có thể không hợp lệ, Eh?

Việc kiểm tra sự tồn tại hoặc khả năng tạo ra các tên đường dẫn có thể không hợp lệ, với giải pháp trên, hầu hết là việc vặt. Chìa khóa nhỏ ở đây là gọi hàm được xác định trước đó trước khi kiểm tra đường dẫn đã truyền:

def is_path_creatable(pathname: str) -> bool:
    '''
    `True` if the current user has sufficient permissions to create the passed
    pathname; `False` otherwise.
    '''
    # Parent directory of the passed path. If empty, we substitute the current
    # working directory (CWD) instead.
    dirname = os.path.dirname(pathname) or os.getcwd()
    return os.access(dirname, os.W_OK)

def is_path_exists_or_creatable(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname for the current OS _and_
    either currently exists or is hypothetically creatable; `False` otherwise.

    This function is guaranteed to _never_ raise exceptions.
    '''
    try:
        # To prevent "os" module calls from raising undesirable exceptions on
        # invalid pathnames, is_pathname_valid() is explicitly called first.
        return is_pathname_valid(pathname) and (
            os.path.exists(pathname) or is_path_creatable(pathname))
    # Report failure on non-fatal filesystem complaints (e.g., connection
    # timeouts, permissions issues) implying this path to be inaccessible. All
    # other exceptions are unrelated fatal issues and should not be caught here.
    except OSError:
        return False

Xongxong. Ngoại trừ không hoàn toàn.

Câu hỏi # 3: Sự tồn tại hoặc khả năng ghi tên đường dẫn có thể không hợp lệ trên Windows

Có một cảnh báo trước. Tất nhiên là có.

Như os.access()tài liệu chính thức thừa nhận:

Lưu ý: Các hoạt động I / O có thể không thành công ngay cả khi os.access()chỉ ra rằng chúng sẽ thành công, đặc biệt đối với các hoạt động trên hệ thống tệp mạng có thể có ngữ nghĩa quyền ngoài mô hình bit quyền POSIX thông thường.

Không ai ngạc nhiên, Windows là nghi phạm thường thấy ở đây. Nhờ sử dụng rộng rãi Danh sách kiểm soát truy cập (ACL) trên hệ thống tệp NTFS, mô hình bit cho phép POSIX đơn giản ánh xạ kém với thực tế cơ bản của Windows. Mặc dù đây (được cho là) ​​không phải là lỗi của Python, nhưng nó vẫn có thể gây lo ngại cho các ứng dụng tương thích với Windows.

Nếu đây là bạn, một sự thay thế mạnh mẽ hơn là điều cần thiết. Nếu đường dẫn đã qua không tồn tại, thay vào đó, chúng tôi cố gắng tạo một tệp tạm thời được đảm bảo sẽ bị xóa ngay lập tức trong thư mục mẹ của đường dẫn đó - một bài kiểm tra khả năng tạo di động hơn (nếu tốn kém):

import os, tempfile

def is_path_sibling_creatable(pathname: str) -> bool:
    '''
    `True` if the current user has sufficient permissions to create **siblings**
    (i.e., arbitrary files in the parent directory) of the passed pathname;
    `False` otherwise.
    '''
    # Parent directory of the passed path. If empty, we substitute the current
    # working directory (CWD) instead.
    dirname = os.path.dirname(pathname) or os.getcwd()

    try:
        # For safety, explicitly close and hence delete this temporary file
        # immediately after creating it in the passed path's parent directory.
        with tempfile.TemporaryFile(dir=dirname): pass
        return True
    # While the exact type of exception raised by the above function depends on
    # the current version of the Python interpreter, all such types subclass the
    # following exception superclass.
    except EnvironmentError:
        return False

def is_path_exists_or_creatable_portable(pathname: str) -> bool:
    '''
    `True` if the passed pathname is a valid pathname on the current OS _and_
    either currently exists or is hypothetically creatable in a cross-platform
    manner optimized for POSIX-unfriendly filesystems; `False` otherwise.

    This function is guaranteed to _never_ raise exceptions.
    '''
    try:
        # To prevent "os" module calls from raising undesirable exceptions on
        # invalid pathnames, is_pathname_valid() is explicitly called first.
        return is_pathname_valid(pathname) and (
            os.path.exists(pathname) or is_path_sibling_creatable(pathname))
    # Report failure on non-fatal filesystem complaints (e.g., connection
    # timeouts, permissions issues) implying this path to be inaccessible. All
    # other exceptions are unrelated fatal issues and should not be caught here.
    except OSError:
        return False

Lưu ý, tuy nhiên, ngay cả điều này có thể là không đủ.

Nhờ Kiểm soát truy cập người dùng (UAC), Windows Vista luôn hoạt động tốt và tất cả các lần lặp lại tiếp theo của nó đều nói dối trắng trợn về các quyền liên quan đến thư mục hệ thống. Khi người dùng không phải Quản trị viên cố gắng tạo tệp trong thư mục chuẩn C:\Windowshoặc C:\Windows\system32thư mục, UAC sẽ cho phép người dùng làm như vậy một cách hời hợt trong khi thực sự cô lập tất cả các tệp đã tạo thành "Cửa hàng ảo" trong hồ sơ của người dùng đó. (Ai có thể ngờ rằng việc lừa dối người dùng sẽ gây ra hậu quả lâu dài có hại?)

Điều này là điên. Đây là Windows.

Chứng minh điều đó

Chúng ta có dám không? Đã đến lúc lái thử các bài kiểm tra trên.

Vì NULL là ký tự duy nhất bị cấm trong tên đường dẫn trên hệ thống tệp hướng UNIX, chúng ta hãy tận dụng điều đó để chứng minh sự thật lạnh lùng, khó hiểu - bỏ qua những trò tai quái không thể bỏ qua của Windows, điều này thực sự khiến tôi bực bội và tức giận ở mức độ tương đương:

>>> print('"foo.bar" valid? ' + str(is_pathname_valid('foo.bar')))
"foo.bar" valid? True
>>> print('Null byte valid? ' + str(is_pathname_valid('\x00')))
Null byte valid? False
>>> print('Long path valid? ' + str(is_pathname_valid('a' * 256)))
Long path valid? False
>>> print('"/dev" exists or creatable? ' + str(is_path_exists_or_creatable('/dev')))
"/dev" exists or creatable? True
>>> print('"/dev/foo.bar" exists or creatable? ' + str(is_path_exists_or_creatable('/dev/foo.bar')))
"/dev/foo.bar" exists or creatable? False
>>> print('Null byte exists or creatable? ' + str(is_path_exists_or_creatable('\x00')))
Null byte exists or creatable? False

Ngoài sự tỉnh táo. Vượt lên trên nỗi đau. Bạn sẽ thấy những lo ngại về tính di động của Python.


3
Đúng, là tôi! Cố gắng kết hợp với nhau một regex xác thực tên đường di động chéo là một bài tập vô ích và được đảm bảo sẽ thất bại đối với các trường hợp cạnh thông thường. Hãy xem xét độ dài tên đường dẫn trên Windows, ví dụ: "Đường dẫn tối đa 32.767 ký tự là gần đúng, vì tiền tố '\\? \' Có thể được hệ thống mở rộng thành chuỗi dài hơn tại thời điểm chạy và sự mở rộng này áp dụng cho tổng độ dài . " Do đó, về mặt kỹ thuật thực sự không khả thi khi tạo một regex chỉ khớp với các tên đường dẫn hợp lệ. Thay vào đó, chỉ cần trì hoãn sang Python sẽ hợp lý hơn nhiều.
Cecil Curry

2
Ah. Tôi (miễn cưỡng) thấy. Bạn đang làm một điều gì đó còn lạ hơn cả việc hack một regex. Vâng, điều đó được đảm bảo sẽ thất bại thậm chí khó hơn. Điều đó cũng hoàn toàn không giải quyết được câu hỏi được đề cập, đó không phải là "Làm cách nào để loại bỏ các chuỗi con không hợp lệ khỏi tên cơ sở dành riêng cho Windows?" (... mà do chính sự thiếu sót của bạn, bạn không giải được - một lần nữa do các trường hợp cạnh) nhưng "Làm cách nào để kiểm tra tính hợp lệ của tên đường dẫn có thể chuyển động chéo và, đối với tên đường dẫn hợp lệ, sự tồn tại hoặc khả năng ghi của các đường dẫn đó?"
Cecil Curry

1
Các ràng buộc dành riêng cho hệ thống tệp chắc chắn là một mối quan tâm hợp lệ - nhưng nó cắt giảm cả hai cách. Đối với các ứng dụng phía trước sử dụng tên đường dẫn tùy ý từ các nguồn không đáng tin cậy, việc đọc thực hiện một cách mù quáng là một đề xuất tốt nhất; trong trường hợp này, việc buộc sử dụng hệ thống tệp gốc không chỉ hợp lý mà còn phải thận trọng. Tuy nhiên, đối với các ứng dụng khác, cơ sở người dùng có thể đủ tin cậy để cấp quyền truy cập hệ thống tệp không bị cấm. Tôi muốn nói rằng nó khá phụ thuộc vào ngữ cảnh. Cảm ơn vì đã chú ý sâu sắc điều này, không ai cả ! Tôi sẽ thêm một cảnh báo ở trên.
Cecil Curry

2
Đối với danh pháp, tôi là một người hâm mộ lớn của tên người thử nghiệm tiền tố bằng is_. Đây là khuyết điểm nhân vật của tôi. Tuy nhiên, cần lưu ý một cách hợp lý: bạn không thể làm hài lòng tất cả mọi người, và đôi khi bạn không thể làm hài lòng bất kỳ ai. ;)
Cecil Curry

1
Trên Fedora 24, python 3.5.3, tên đường dẫn có ký tự null được nhúng sẽ ném: ValueError: byte null được nhúng… cần thêm: `` 'ngoại trừ ValueError như exc: return False' '' trước hoặc sau bẫy TypeError.
mMerlin

47
if os.path.exists(filePath):
    #the file is there
elif os.access(os.path.dirname(filePath), os.W_OK):
    #the file does not exists but write privileges are given
else:
    #can not write there

Lưu ý rằng path.existscó thể thất bại vì nhiều lý do hơn chỉ the file is not therevì vậy bạn có thể phải thực hiện các bài kiểm tra tốt hơn như kiểm tra xem thư mục chứa có tồn tại hay không, v.v.


Sau cuộc thảo luận của tôi với OP, thì vấn đề chính dường như là, tên tệp có thể chứa các ký tự không được hệ thống tệp cho phép. Tất nhiên chúng cần phải được gỡ bỏ nhưng OP muốn duy trì khả năng đọc của con người nhiều như hệ thống tệp cho phép.

Đáng buồn là tôi không biết bất kỳ giải pháp tốt cho điều này. Tuy nhiên câu trả lời của Cecil Curry sẽ xem xét kỹ hơn việc phát hiện ra vấn đề.


Không. Tôi cần trả về true nếu tệp ở đường dẫn tồn tại hoặc có thể được tạo . Tôi cần trả về false nếu đường dẫn không hợp lệ (do chứa các ký tự không hợp lệ trên windows).
Tên giả,

or can be createdtôi đã không đọc điều đó từ câu hỏi của bạn. Việc đọc các quyền sẽ phụ thuộc vào Platfrom ở một mức độ nào đó.
Không ai di chuyển khỏi ĐN

1
@Fake Name: Có, nó sẽ loại bỏ một số phụ thuộc vào nền tảng nhưng vẫn có một số nền tảng cung cấp những thứ mà những nền tảng khác không có và không có cách nào dễ dàng để kết hợp điều đó cho tất cả chúng. Tôi đã cập nhật câu trả lời của mình, hãy xem ở đó.
Không ai di chuyển khỏi SE

1
Tôi không biết tại sao câu trả lời này được ủng hộ. Nó không đến từ xa để giải quyết câu hỏi cốt lõi - mà ngắn gọn là: "Làm ơn hãy xác thực tên đường dẫn?" Xác thực quyền đường dẫn là một câu hỏi phụ (và phần lớn có thể bỏ qua) ở đây. Mặc dù lệnh gọi đến os.path.exists(filePath)về mặt kỹ thuật nêu ra các ngoại lệ đối với tên đường dẫn không hợp lệ, nhưng các ngoại lệ đó sẽ cần được xác định rõ ràng và phân biệt với các ngoại lệ không liên quan khác. Hơn nữa, cùng một cuộc gọi trả về Falsetrên các đường dẫn hiện có mà người dùng hiện tại không có quyền đọc. Nói tóm lại là tính xấu.
Cecil Curry

1
@CecilCurry: Để trả lời câu hỏi của bạn: Hãy xem lịch sử chỉnh sửa của câu hỏi. Như với hầu hết các câu hỏi, ban đầu nó không rõ ràng như vậy và thậm chí bây giờ chỉ riêng từ ngữ của tiêu đề có thể được hiểu khác hơn bạn nói.
Không ai rời khỏi SE

9

Với Python 3, làm thế nào về:

try:
    with open(filename, 'x') as tempfile: # OSError if file exists or is invalid
        pass
except OSError:
    # handle error here

Với tùy chọn 'x', chúng tôi cũng không phải lo lắng về điều kiện cuộc đua. Xem tài liệu tại đây .

Bây giờ, điều này SẼ tạo một tệp tạm thời rất được yêu thích nếu nó chưa tồn tại - trừ khi tên không hợp lệ. Nếu bạn có thể sống với điều đó, nó sẽ đơn giản hóa mọi thứ rất nhiều.


2
Tại thời điểm này, dự án cần điều này đã vượt xa mức mà một câu trả lời thậm chí có liên quan mà tôi thực sự không thể chấp nhận một câu trả lời.
Tên giả mạo

Trớ trêu thay, câu trả lời thực tế là không đủ tốt. Bất kể tôi cho rằng bạn có thể xem liệu tệp có tồn tại hay không. Nếu có, hãy cố gắng sao chép tệp ở nơi khác, sau đó cố gắng ghi đè.
The Matt

5
open(filename,'r')   #2nd argument is r and not w

sẽ mở tệp hoặc báo lỗi nếu tệp không tồn tại. Nếu có lỗi, bạn có thể thử ghi vào đường dẫn, nếu không thể thì bạn gặp lỗi thứ hai

try:
    open(filename,'r')
    return True
except IOError:
    try:
        open(filename, 'w')
        return True
    except IOError:
        return False

Ngoài ra, hãy xem ở đây về quyền trên windows


1
Để tránh phải hủy liên kết () tệp thử nghiệm một cách rõ ràng, bạn có thể sử dụng cách tempfile.TemporaryFile()này sẽ tự động hủy tệp tạm thời khi nó vượt ra khỏi phạm vi.
D_Bye

@FakeName Mã khác nhau, tôi có thể đã sử dụng os.access ở phần thứ hai nhưng nếu bạn theo liên kết mà tôi cung cấp, bạn sẽ thấy rằng đó không phải là một ý tưởng hay, điều này khiến bạn có tùy chọn cố gắng thực sự mở con đường để viết.
vikki

Tôi đang xây dựng đường dẫn của mình với os.path.join, vì vậy tôi không gặp vấn đề về việc thoát. Hơn nữa, tôi không thực sự gặp vấn đề về quyền thư mục . Tôi đang gặp sự cố về tên thư mục (và tên tệp) .
Tên giả vào

@FakeName trong trường hợp đó bạn chỉ cần thử và mở nó (bạn không cần viết), python sẽ báo lỗi nếu filenamechứa các ký tự không hợp lệ. Tôi đã chỉnh sửa câu trả lời
vikki

1
@HelgaIliashenko Mở để ghi sẽ ghi đè lên tệp hiện có (làm cho tệp trống) ngay cả khi bạn đóng tệp ngay lập tức mà không ghi vào tệp đó. Đó là lý do tại sao tôi mở để đọc trước tiên vì theo cách đó, nếu bạn không gặp lỗi thì bạn biết rằng có một tệp hiện có.
vikki 17/07/17

-7

thử os.path.existsđiều này sẽ kiểm tra đường dẫn và trả về Truenếu tồn tại và Falsenếu không.


1
Không. Tôi cần trả về true nếu tệp ở đường dẫn tồn tại hoặc có thể được tạo . Tôi cần trả về false nếu đường dẫn không hợp lệ (do chứa các ký tự không hợp lệ trên windows).
Tên giả vào

loại ký tự không hợp lệ?
Nilesh

Dunno - đó là nền tảng cụ thể.
Tên giả vào

2
Hệ thống tệp cụ thể, thực sự.
Piotr Kalinowski
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.