Hầu hết các cách pythonic để xóa một tập tin có thể không tồn tại


453

Tôi muốn xóa các tập tin filenamenếu nó tồn tại. Có đúng không?

if os.path.exists(filename):
    os.remove(filename)

Có cách nào tốt hơn? Một cách một dòng?


7
Bạn có muốn thử xóa một tệp nếu nó tồn tại (và thất bại nếu bạn thiếu quyền) hoặc thực hiện xóa nỗ lực tốt nhất và không bao giờ có lỗi ném lại vào mặt bạn?
Donal Fellows

Tôi muốn làm "trước đây" những gì @DonalFellows nói. Vì thế, tôi đoán mã gốc của Scott sẽ là một cách tiếp cận tốt?
LarsH

Tạo một hàm được gọi unlinkvà đặt nó trong không gian tên PHP.
lama12345

1
@LarsH Xem khối mã thứ hai của câu trả lời được chấp nhận. Nó phục hồi ngoại lệ nếu ngoại lệ là bất cứ điều gì ngoại trừ lỗi "không có tệp hoặc thư mục như vậy".
jpmc26

Câu trả lời:


613

Một cách pythonic hơn sẽ là:

try:
    os.remove(filename)
except OSError:
    pass

Mặc dù điều này thậm chí còn có nhiều dòng hơn và trông rất xấu xí, nhưng nó tránh được các cuộc gọi không cần thiết đến os.path.exists()và tuân theo quy ước python về việc lạm dụng các ngoại lệ.

Có thể đáng để viết một hàm để làm điều này cho bạn:

import os, errno

def silentremove(filename):
    try:
        os.remove(filename)
    except OSError as e: # this would be "except OSError, e:" before Python 2.6
        if e.errno != errno.ENOENT: # errno.ENOENT = no such file or directory
            raise # re-raise exception if a different error occurred

17
Nhưng điều này có vượt qua được không nếu thao tác xóa không thành công (chỉ đọc hệ thống tệp hoặc một số sự cố không mong muốn khác)?
Scott C Wilson

135
Ngoài ra, thực tế là tệp tồn tại khi os.path.exists()được thực thi không có nghĩa là nó tồn tại khi os.remove()được thực thi.
loại

8
+1 của tôi, nhưng lạm dụng các ngoại lệ không phải là quy ước Python :) Hay là vậy?
pepr

8
@pepr Tôi chỉ hài hước chỉ trích làm thế nào các ngoại lệ là một phần của hành vi bình thường trong python. Ví dụ, các trình vòng lặp phải đưa ra các ngoại lệ để dừng lặp lại.
Matt

5
+1 vì tôi không thể +2. Bên cạnh việc có nhiều Pythonic, điều này thực sự chính xác, trong khi bản gốc thì không, vì lý do này khá được đề xuất. Điều kiện cuộc đua như thế dẫn đến lỗ hổng bảo mật, lỗi khó sửa chữa, v.v.
abarnert

159

Tôi thích loại bỏ một ngoại lệ hơn là kiểm tra sự tồn tại của tệp để tránh lỗi TOCTTOU . Câu trả lời của Matt là một ví dụ tốt về điều này, nhưng chúng ta có thể đơn giản hóa nó một chút trong Python 3, bằng cách sử dụng contextlib.suppress():

import contextlib

with contextlib.suppress(FileNotFoundError):
    os.remove(filename)

Nếu filenamelà một pathlib.Pathđối tượng thay vì một chuỗi, chúng ta có thể gọi .unlink()phương thức của nó thay vì sử dụngos.remove() . Theo kinh nghiệm của tôi, các đối tượng Path hữu ích hơn các chuỗi để thao tác hệ thống tập tin.

Vì mọi thứ trong câu trả lời này là độc quyền cho Python 3, nó cung cấp thêm một lý do để nâng cấp.


7
Đây là cách pythonic nhất như vào tháng 12 năm 2015. Python vẫn tiếp tục phát triển.
Mayank Jaiswal

2
Tôi không tìm thấy phương thức remove () nào cho các đối tượng pathlib.Path trên Python 3.6
BrianHVB

1
@jeffbyrnes: Tôi gọi đó là sự vi phạm Zen của Python: "Nên có một-- và tốt nhất là chỉ có một cách - rõ ràng để làm điều đó." Nếu bạn có hai phương thức đã làm điều tương tự, bạn sẽ kết thúc với một hỗn hợp của chúng trong việc chạy mã nguồn, điều này sẽ khiến người đọc khó theo dõi hơn. Tôi nghi ngờ họ muốn sự nhất quán với unlink(2), đó là giao diện lâu đời nhất ở đây.
Kevin

1
@nivk: Nếu bạn cần một exceptmệnh đề, thì bạn nên sử dụng try/ except. Không thể rút ngắn một cách có ý nghĩa, bởi vì bạn phải có một dòng để giới thiệu khối đầu tiên, chính khối đó, một dòng để giới thiệu khối thứ hai, và sau đó là khối đó, vì vậy try/ exceptđã hết sức có thể.
Kevin

1
Thật đáng để chỉ ra rằng không giống như một khối thử / ngoại trừ, giải pháp này có nghĩa là bạn không phải loay hoay tạo ra một ngoại lệ để đảm bảo rằng các số liệu bảo hiểm kiểm tra có liên quan.
thclark

50

os.path.existstrả về Truecho các thư mục cũng như các tập tin. Xem xét sử dụng os.path.isfileđể kiểm tra xem các tập tin tồn tại thay thế.


4
Bất cứ khi nào chúng tôi kiểm tra sự tồn tại và sau đó loại bỏ dựa trên thử nghiệm đó, chúng tôi sẽ tự mở ra một điều kiện cuộc đua. (Điều gì sẽ xảy ra nếu tập tin biến mất ở giữa?)
Alex L

34

Theo tinh thần câu trả lời của Andy Jones, làm thế nào về một hoạt động ternary đích thực:

os.remove(fn) if os.path.exists(fn) else None

41
Lạm dụng xấu xí của chim nhạn.
bgusach

19
@BrianHVB Bởi vì chim nhạn ở đó để lựa chọn giữa hai giá trị dựa trên một điều kiện, không phải phân nhánh.
bgusach

1
Tôi không muốn sử dụng ngoại lệ để kiểm soát dòng chảy. Chúng làm cho mã khó hiểu và quan trọng hơn có thể che giấu một số lỗi khác xảy ra (như vấn đề cấp phép chặn xóa tệp) sẽ gây ra lỗi im lặng.
Ed King

11
Đây không phải là nguyên tử. Các tập tin có thể bị xóa giữa các cuộc gọi để tồn tại và loại bỏ. An toàn hơn để thử hoạt động và cho phép nó thất bại.
ConnorWGarvey

1
@ nam-g-vu Chỉ cần FYI, tôi đã khôi phục chỉnh sửa của bạn vì về cơ bản bạn chỉ cần thêm cú pháp của người hỏi ban đầu như một cách thay thế. Vì họ đang tìm kiếm thứ gì đó khác hơn, tôi không cảm thấy rằng chỉnh sửa là nguyên nhân cho câu trả lời cụ thể này.
Tim

9

Một cách khác để biết liệu tệp (hoặc tệp) có tồn tại hay không và để xóa tệp đó là sử dụng mô-đun toàn cầu.

from glob import glob
import os

for filename in glob("*.csv"):
    os.remove(filename)

Glob tìm thấy tất cả các tệp có thể chọn mẫu có ký tự đại diện * nix và lặp lại danh sách.


9

Kể từ Python 3.8, hãy sử dụng missing_ok=Truepathlib.Path.unlink( tài liệu ở đây )

from pathlib import Path

my_file = Path("./dir1/dir2/file.txt")

# Python 3.8+
my_file.unlink(missing_ok=True)

# Python 3.7 and earlier
if my_file.exists():
    my_file.unlink()

1
Câu trả lời tốt nhất cho python3 thực tế theo ý kiến ​​của tôi.
mrgnw


6
if os.path.exists(filename): os.remove(filename)

là một lớp lót.

Nhiều người trong số các bạn có thể không đồng ý - có thể vì những lý do như xem xét đề xuất sử dụng chim nhạn "xấu xí" - nhưng điều này đặt ra câu hỏi liệu chúng ta có nên lắng nghe mọi người sử dụng các tiêu chuẩn xấu xí khi họ gọi một thứ không chuẩn là "xấu xí".


3
Đây là sạch - Tôi không muốn sử dụng ngoại lệ để kiểm soát dòng chảy. Chúng làm cho mã khó hiểu và quan trọng hơn có thể che giấu một số lỗi khác xảy ra (như vấn đề cấp phép chặn xóa tệp) sẽ gây ra lỗi im lặng.
Ed King

2
Nó không đẹp bởi vì nó giả sử chỉ có một quá trình sẽ sửa đổi tên tệp. Nó không phải là nguyên tử. Đó là an toàn và chính xác để cố gắng hoạt động và thất bại duyên dáng. Thật khó chịu khi Python không thể tiêu chuẩn hóa. Nếu chúng tôi có một thư mục, chúng tôi sẽ sử dụng tắt máy và nó sẽ hỗ trợ chính xác những gì chúng tôi muốn.
ConnorWGarvey


1

Một cái gì đó như thế này? Tận dụng lợi thế của đánh giá ngắn mạch. Nếu tệp không tồn tại, toàn bộ điều kiện không thể đúng, vì vậy python sẽ không bận tâm đến việc đánh giá phần thứ hai.

os.path.exists("gogogo.php") and os.remove("gogogo.php")

25
Đây chắc chắn không phải là "Pythonic" thực tế, đó là điều Guido đặc biệt cảnh báo và gọi là "lạm dụng" các nhà khai thác boolean.
abarnert

1
ồ, tôi đồng ý - một phần của câu hỏi được hỏi theo cách một dòng và đây là điều đầu tiên xuất hiện trong đầu tôi
Andy Jones

4
Chà, bạn cũng có thể biến nó thành một lớp lót bằng cách chỉ xóa dòng mới sau dấu hai chấm Hoặc, hay hơn nữa, Guide miễn cưỡng thêm biểu thức if để ngăn mọi người "lạm dụng toán tử boolean", và có một cơ hội tuyệt vời để chứng minh rằng bất cứ điều gì cũng có thể bị lạm dụng: os.remove ("gogogo.php") nếu os.path.exists ("gogogo.php") khác Không có. :)
abarnert

0

Một đề nghị KISS:

def remove_if_exists(filename):
  if os.path.exists(filename):
    os.remove(filename)

Và sau đó:

remove_if_exists("my.file")

1
Nếu bạn phải viết toàn bộ một chức năng, nó sẽ bỏ lỡ điểm của một lớp lót
Ion Lesan

@Ion Lesan OP là cách tốt nhất để giải quyết vấn đề này. Một lớp lót không bao giờ là một cách tốt hơn nếu nó gây nguy hiểm cho khả năng đọc.
Baz

Với định nghĩa rộng rãi về "tốt nhất", tôi sẽ không tranh luận theo nghĩa này, mặc dù nó rõ ràng bị ảnh hưởng bởi TOCTOU. Và chắc chắn không phải là một giải pháp KISS.
Ion Lesan

@Matt Đúng nhưng không một số giải pháp được cung cấp ở đây bị vấn đề này?

0

Đây là một giải pháp khác:

if os.path.isfile(os.path.join(path, filename)):
    os.remove(os.path.join(path, filename))

0

Một giải pháp khác với thông điệp của riêng bạn trong ngoại lệ.

import os

try:
    os.remove(filename)
except:
    print("Not able to delete the file %s" % filename)

-1

Tôi đã sử dụng rmcó thể buộc phải xóa các tệp không tồn tại với --preserve-roottư cách là một tùy chọn rm.

--preserve-root
              do not remove `/' (default)

rm --help | grep "force"
  -f, --force           ignore nonexistent files and arguments, never prompt

Chúng ta cũng có thể sử dụng safe-rm ( sudo apt-get install safe-rm)

Safe-rm là một công cụ an toàn nhằm ngăn chặn việc vô tình xóa các tệp quan trọng bằng cách thay thế / bin / rm bằng trình bao bọc, kiểm tra các đối số đã cho đối với danh sách đen các tệp và thư mục có thể định cấu hình không bao giờ bị xóa.

Đầu tiên tôi kiểm tra xem đường dẫn thư mục / tập tin có tồn tại hay không. Điều này sẽ ngăn cài đặt biến tệpToRemove /thư mụcToRemove to the string-r / `.


import os, subprocess

fileToRemove = '/home/user/fileName';
if os.path.isfile(fileToRemove):
   subprocess.run(['rm', '-f', '--preserve-root', fileToRemove]
   subprocess.run(['safe-rm', '-f', fileToRemove]

1
Sử dụng một vỏ cho một cái gì đó tầm thường này là quá mức cần thiết và phương pháp này cũng sẽ không hoạt động đa nền tảng (ví dụ: Windows).
Nabla

4
Sử dụng shell thay vì thư viện tiêu chuẩn (ví dụ os.remove) luôn là một trong những cách ít nhất để làm việc gì đó. Ví dụ, bạn phải tự xử lý các lỗi được trả về bởi trình bao.
Nabla

1
Tôi đã thêm câu trả lời của tôi để sử dụng rmmột cách an toàn và ngăn chặn rm -r /. @JonBrave
alper

1
rm -f --preserve-rootkhông đủ tốt ( --preserve-rootdù sao cũng có thể là mặc định). Tôi đã đưa ra -r / một ví dụ , nếu nó -r /homehoặc bất cứ điều gì? Bạn có thể muốn rm -f -- $fileToRemove, nhưng đó không phải là vấn đề.
JonBrave

3
Không phải cách bạn đã sử dụng nó, với một tên biến (biến môi trường), và không trích dẫn, và không bảo vệ, không. Và không cho câu hỏi này, không. Phơi bày sự không mong muốn os.system('rm ...')là vô cùng nguy hiểm, xin lỗi.
JonBrave
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.