วิธีไพ ธ อนิกส่วนใหญ่ในการลบไฟล์ซึ่งอาจไม่มีอยู่


453

ฉันต้องการลบไฟล์filenameหากมีอยู่ มันเหมาะสมที่จะพูด

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

มีวิธีที่ดีกว่า? ทางเดียวหรือไม่


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

ฉันต้องการทำ "อดีต" ของสิ่งที่ @DonalFellows พูด เพื่อที่ฉันเดารหัสเดิมของ Scott จะเป็นวิธีที่ดี?
LarsH

ทำให้ฟังก์ชั่นที่เรียกว่าunlinkและวางไว้ใน namespace PHP
lama12345

1
@LarsH ดูบล็อกรหัสที่สองของคำตอบที่ยอมรับ มันจะได้รับการยกเว้นถ้าข้อยกเว้นนั้นเป็นอะไรนอกจากข้อผิดพลาด "ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว"
jpmc26

คำตอบ:


614

วิธี pythonic เพิ่มเติมจะเป็น:

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

แม้ว่าจะใช้สายมากขึ้นและดูน่าเกลียดมาก แต่ก็ช่วยหลีกเลี่ยงการโทรที่ไม่จำเป็นos.path.exists()และปฏิบัติตามแบบแผนของการใช้ข้อยกเว้นที่มากเกินไป

มันอาจจะคุ้มค่าที่จะเขียนฟังก์ชั่นสำหรับคุณ:

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
แต่สิ่งนี้จะเกิดขึ้นหากการดำเนินการลบล้มเหลว (อ่านอย่างเดียวระบบไฟล์หรือปัญหาอื่น ๆ ที่ไม่คาดคิด)
Scott C Wilson

137
นอกจากนี้ความจริงที่ว่าไฟล์นั้นมีอยู่เมื่อos.path.exists()เรียกใช้งานไม่ได้หมายความว่ามีอยู่เมื่อos.remove()เรียกใช้งาน
kindall

8
+1 ของฉัน แต่การใช้ข้อยกเว้นมากเกินไปไม่ใช่แบบแผนของ Python :) หรือเป็นเพราะอะไร
pepr

8
@ pepr ฉันเพียงแค่วิจารณ์อย่างตลกขบขันว่าข้อยกเว้นเป็นส่วนหนึ่งของพฤติกรรมปกติในหลามอย่างไร ตัวอย่างเช่นตัววนซ้ำต้องยกข้อยกเว้นเพื่อหยุดการวนซ้ำ
แมตต์

5
+1 เพราะฉันไม่สามารถ +2 นอกเหนือจากการเป็น Pythonic ที่มากขึ้นแล้วอันนี้ก็ถูกต้องจริงในขณะที่ต้นฉบับไม่ได้สำหรับเหตุผลที่แนะนำทั้งหมด สภาพการแข่งขันเช่นนั้นนำไปสู่ช่องโหว่ความปลอดภัยข้อผิดพลาดที่ยากต่อการ
ลอกเลียนแบบ

160

ฉันต้องการระงับข้อยกเว้นแทนที่จะตรวจสอบการมีอยู่ของไฟล์เพื่อหลีกเลี่ยงข้อผิดพลาดTOCTTOU คำตอบของ Matt เป็นตัวอย่างที่ดีของเรื่องนี้ แต่เราสามารถทำให้มันง่ายขึ้นเล็กน้อยภายใต้ Python 3 โดยใช้contextlib.suppress():

import contextlib

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

หากfilenameเป็นpathlib.Pathวัตถุแทนสตริงเราสามารถเรียกมันวิธีการแทนการใช้.unlink() os.remove()ในประสบการณ์ของฉันวัตถุเส้นทางมีประโยชน์มากกว่าสตริงสำหรับการจัดการระบบไฟล์

เนื่องจากทุกอย่างในคำตอบนี้เป็นเอกสิทธิ์ของ Python 3 จึงเป็นอีกเหตุผลหนึ่งที่ทำให้อัปเกรด


8
วิธีนี้เป็นวิธีการแบบไพทอนมากที่สุดในเดือนธันวาคม 2558 Python ยังคงพัฒนาต่อไป
Mayank Jaiswal

2
ฉันพบว่าไม่มีการลบ () วิธีการสำหรับวัตถุ pathlib.Path บน Python 3.6
BrianHVB

1
@jeffbyrnes: ฉันจะเรียกว่าการละเมิดของ Zen of Python: "ควรมีอย่างใดอย่างหนึ่ง - และดีกว่าเพียงหนึ่ง - วิธีที่ชัดเจนที่จะทำมัน." หากคุณมีสองวิธีที่ทำในสิ่งเดียวกันคุณจะต้องมีการผสมผสานระหว่างการรันซอร์สโค้ดซึ่งจะทำให้ผู้อ่านติดตามได้ยากขึ้น ฉันสงสัยว่าพวกเขาต้องการความสอดคล้องunlink(2)ซึ่งเป็นอินเทอร์เฟซที่เกี่ยวข้องที่เก่าแก่ที่สุดที่นี่
เควิน

1
@nivk: ถ้าคุณจำเป็นต้องมีexceptข้อแล้วคุณควรใช้/try exceptไม่สามารถย่อให้สั้นลงอย่างมีความหมายได้เนื่องจากคุณจะต้องมีบรรทัดเพื่อแนะนำบล็อกแรกบล็อกนั้นเองบรรทัดเพื่อแนะนำบล็อกที่สองจากนั้นบล็อกนั้นดังนั้นtry/ exceptจึงสั้นที่สุด
Kevin

1
เป็นมูลค่าชี้ให้เห็นว่าแตกต่างจากลอง / ยกเว้นบล็อกการแก้ปัญหานี้หมายความว่าคุณไม่ต้องยุ่งเกี่ยวกับการสร้างข้อยกเว้นเพื่อให้แน่ใจว่าการวัดการครอบคลุมการทดสอบมีความเกี่ยวข้อง
thclark

50

os.path.existsส่งคืนTrueสำหรับโฟลเดอร์รวมถึงไฟล์ ลองใช้os.path.isfileเพื่อตรวจสอบว่ามีไฟล์อยู่หรือไม่


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

34

ด้วยจิตวิญญาณของคำตอบของ Andy Jones วิธีการดำเนินงานที่ประกอบไปด้วยของจริง:

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

41
การใช้ ternaries ในทางที่ผิดน่าเกลียด
bgusach

19
@BrianHVB เนื่องจากผู้ประกอบการมีให้เลือกระหว่างสองค่าโดยยึดตามเงื่อนไขไม่ใช่การแยกสาขา
bgusach

1
ฉันไม่ชอบใช้ข้อยกเว้นสำหรับการควบคุมการไหล พวกเขาทำให้รหัสยากที่จะเข้าใจและที่สำคัญสามารถปกปิดข้อผิดพลาดอื่น ๆ ที่เกิดขึ้น (เช่นปัญหาการอนุญาตบล็อกไฟล์ลบ) ซึ่งจะทำให้เกิดความล้มเหลวเงียบ
Ed King

11
นี่ไม่ใช่อะตอม ไฟล์สามารถลบได้ระหว่างการโทรไปยังมีอยู่และลบออก การพยายามดำเนินการและปลอดภัยกว่าจะทำให้ล้มเหลว
ConnorWGarvey

1
@ nam-g-vu เพียงแค่ FYI ฉันย้อนกลับการแก้ไขของคุณเพราะคุณเพิ่งเพิ่มไวยากรณ์ของผู้ถามดั้งเดิมเป็นทางเลือก เนื่องจากพวกเขากำลังมองหาบางอย่างที่แตกต่างไปจากนั้นฉันไม่รู้สึกว่าการแก้ไขนั้นมีประโยชน์สำหรับคำตอบนี้
Tim Keating

11

ตั้งแต่ Python 3.8 ใช้missing_ok=Trueและpathlib.Path.unlink( เอกสารที่นี่ )

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
คำตอบที่ดีที่สุดสำหรับ python3 ที่ใช้งานจริงในความคิดของฉัน
mrgnw

9

อีกวิธีหนึ่งในการทราบว่ามีไฟล์ (หรือไฟล์) อยู่หรือไม่และจะลบออกหรือไม่โดยใช้โมดูล glob

from glob import glob
import os

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

Glob ค้นหาไฟล์ทั้งหมดที่สามารถเลือกรูปแบบด้วย wildcard * nix และวนซ้ำรายการ


7

คำตอบของ Matt เป็นคำตอบที่ดีสำหรับ Pythons ที่มีอายุมากกว่าและคำตอบที่ถูกของ Kevinสำหรับคำตอบใหม่

หากคุณไม่ต้องการคัดลอกฟังก์ชั่นสำหรับsilentremoveฟังก์ชั่นนี้จะปรากฏในpath.pyเป็นremove_p :

from path import Path
Path(filename).remove_p()

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

เป็นหนึ่งซับ

พวกคุณหลายคนอาจไม่เห็นด้วย - อาจเป็นเพราะเหตุผลเช่นการพิจารณาการใช้ ternaries "น่าเกลียด" - แต่สิ่งนี้ทำให้เกิดคำถามว่าเราควรฟังคนที่เคยใช้มาตรฐานที่น่าเกลียดเมื่อพวกเขาเรียกสิ่งที่ไม่ได้มาตรฐานหรือไม่


3
นี่สะอาด - ฉันไม่ชอบใช้ข้อยกเว้นสำหรับการควบคุมการไหล พวกเขาทำให้รหัสยากที่จะเข้าใจและที่สำคัญสามารถปกปิดข้อผิดพลาดอื่น ๆ ที่เกิดขึ้น (เช่นปัญหาการอนุญาตบล็อกไฟล์ลบ) ซึ่งจะทำให้เกิดความล้มเหลวเงียบ
Ed King

2
ไม่สวยเพราะถือว่ามีเพียงกระบวนการเดียวเท่านั้นที่จะแก้ไขชื่อไฟล์ มันไม่ใช่อะตอม มันปลอดภัยและถูกต้องในการพยายามดำเนินการและล้มเหลวอย่างสง่างาม มันน่ารำคาญที่ Python ไม่สามารถสร้างมาตรฐานได้ หากเรามีไดเรกทอรีเราจะใช้ shutil และมันจะสนับสนุนสิ่งที่เราต้องการ
ConnorWGarvey

2

ใน Python 3.4 หรือเวอร์ชั่นที่ใหม่กว่าวิธีไพ ธ อนจะเป็นดังนี้:

import os
from contextlib import suppress

with suppress(OSError):
    os.remove(filename)

3
นี้ไม่แตกต่างจาก substantively คำตอบให้ที่นี่
chb

1

อะไรแบบนี้? ใช้ประโยชน์จากการประเมินการลัดวงจร หากไฟล์ไม่มีอยู่เงื่อนไขทั้งหมดไม่เป็นจริงดังนั้น python จะไม่รบกวนการประเมินส่วนที่สอง

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

25
นี่ไม่ใช่ "เพิ่มเติมไพทอน" แน่นอนในความเป็นจริงมันเป็นสิ่งที่กุยโดเตือนโดยเฉพาะและอ้างถึง "การละเมิด" ของผู้ให้บริการบูลีน
abarnert

1
โอ้ฉันเห็นด้วย - ส่วนหนึ่งของคำถามถามหาวิธีหนึ่งบรรทัดและนี่คือสิ่งแรกที่โผล่เข้ามาในหัวของฉัน
Andy Jones

4
คุณสามารถทำให้มันเป็นหนึ่งซับได้ด้วยการลบ newline หลังเครื่องหมายโคลอน ... หรือดียิ่งขึ้นคู่มือแนะนำอย่างไม่สุภาพเพิ่มการแสดงออกหากหยุดไม่ให้ผู้คน "ใช้โอเปอเรเตอร์บูลีน" และมีโอกาสพิสูจน์ได้ดี สิ่งที่สามารถถูกทำร้ายได้: os.remove ("gogogo.php") หาก os.path.exists ("gogogo.php") อื่นไม่มี :)
abarnert

0

ข้อเสนอ KISS:

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

แล้ว:

remove_if_exists("my.file")

1
หากคุณต้องเขียนฟังก์ชั่นทั้งหมดมันจะพลาดจุดหนึ่งตอร์ปิโด
Ion Lesan

@Ion Lesan OP คือวิธีที่ "ดีที่สุด" ในการแก้ไขปัญหานี้ ซับหนึ่งไม่เคยเป็นวิธีที่ดีกว่าถ้ามันเป็นอันตรายต่อการอ่าน
Baz

ด้วยคำจำกัดความกว้าง ๆ ที่ว่า "ดีที่สุด" ฉันจะไม่โต้แย้งในแง่นี้แม้ว่าจะได้รับผลกระทบอย่างชัดเจนจาก TOCTOU และไม่ใช่ทางออกของ KISS แน่นอน
ไอออน Lesan

@ Matt True แต่ไม่ได้มีการแก้ไขปัญหาจำนวนมากที่นำเสนอที่นี่จากปัญหานี้หรือไม่
Baz


0

โซลูชันอื่นที่มีข้อความของคุณเองยกเว้น

import os

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

-1

ฉันได้ใช้rmซึ่งสามารถบังคับให้ลบไฟล์ที่ไม่มีอยู่ด้วยเป็นตัวเลือกให้กับ--preserve-rootrm

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

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

เรายังสามารถใช้safe-rm ( sudo apt-get install safe-rm)

Safe-rm เป็นเครื่องมือด้านความปลอดภัยที่มีวัตถุประสงค์เพื่อป้องกันการลบไฟล์สำคัญโดยไม่ได้ตั้งใจโดยแทนที่ / bin / rm ด้วย wrapper ซึ่งตรวจสอบข้อโต้แย้งที่กำหนดกับบัญชีดำของไฟล์และไดเรกทอรีที่กำหนดค่าได้ซึ่งไม่ควรลบออก

ก่อนอื่นฉันจะตรวจสอบว่ามีเส้นทางโฟลเดอร์ / ไฟล์อยู่หรือไม่ สิ่งนี้จะป้องกันการตั้งค่าตัวแปร fileToRemove /folderToRemove 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
การใช้เปลือกหอยสำหรับสิ่งเล็ก ๆ น้อย ๆ ที่เกินความจริงและวิธีการนี้จะไม่ทำงานข้ามแพลตฟอร์ม (เช่น Windows)
Nabla

4
การใช้เชลล์แทนไลบรารี่มาตรฐาน (ตัวอย่างเช่น os.remove) เป็นหนึ่งในวิธีการทำงานแบบไพ ธ อน / คลีนที่น้อยที่สุดในการทำบางสิ่งบางอย่าง ตัวอย่างเช่นคุณต้องจัดการข้อผิดพลาดที่เชลล์ส่งคืนด้วยตนเอง
Nabla

1
ผมเพิ่มคำตอบของฉันที่จะใช้อย่างปลอดภัยและป้องกันไม่ให้rm rm -r /@JonBrave
alper

1
rm -f --preserve-rootไม่ดีพอ ( --preserve-rootอาจเป็นค่าเริ่มต้นอยู่แล้ว) ฉันยก-r / ตัวอย่างเช่นถ้ามันเป็น-r /homeหรืออะไร คุณอาจต้องการrm -f -- $fileToRemoveแต่นั่นไม่ใช่ประเด็น
JonBrave

3
ไม่ใช่วิธีที่คุณใช้ด้วยชื่อตัวแปร (ตัวแปรสภาพแวดล้อม) และไม่มีการอ้างอิงและไม่มีการป้องกันไม่ใช่ และไม่ใช่สำหรับคำถามนี้ไม่ใช่ การเปิดเผยสิ่งที่ไม่ระวังos.system('rm ...')เป็นอันตรายอย่างยิ่งขอโทษ
JonBrave
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.