การปิดไฟล์มีความสำคัญหรือไม่


149

ใน Python หากคุณเปิดไฟล์โดยไม่ต้องโทรclose()หรือปิดไฟล์ แต่ไม่ได้ใช้try- finallyหรือwithคำสั่ง "" นี่เป็นปัญหาหรือไม่ หรือว่าเป็นวิธีการเข้ารหัสที่เพียงพอที่จะใช้กับคอลเลกชัน Python เพื่อปิดไฟล์ทั้งหมดหรือไม่ ตัวอย่างเช่นหากทำสิ่งนี้:

for line in open("filename"):
    # ... do stuff ...

... นี่เป็นปัญหาเนื่องจากไฟล์ไม่สามารถปิดได้และอาจมีข้อยกเว้นเกิดขึ้นซึ่งทำให้ไม่สามารถปิดไฟล์ได้ หรือมันจะปิดอย่างแน่นอนในตอนท้ายของforคำสั่งเพราะไฟล์ออกไปนอกขอบเขต?


13
ไฟล์ที่ไม่ได้ออกไปจากขอบเขตที่ส่วนท้ายของforบล็อก จำนวนการอ้างอิงของมันจะเป็นศูนย์ทำให้ปิดโดยอัตโนมัติ แต่เฉพาะฟังก์ชันคลาสและโมดูลที่กำหนดขอบเขตใน Python ไม่ใช่คำสั่งผสมอื่น ๆ
agf

18
มันไม่ใช่ปัญหาเว้นแต่เป็นปัญหา ในระดับระบบปฏิบัติการไฟล์ใด ๆ ที่เปิดโดยสคริปต์จะถูกปิดเมื่อสคริปต์ออกดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับการปิดไฟล์ในสคริปต์เครื่องมือที่ถูกทิ้ง อย่างไรก็ตามโปรเซสมีข้อ จำกัด เกี่ยวกับจำนวนไฟล์ที่เปิดซึ่งสามารถดูแลรักษาได้ดังนั้นสคริปต์ที่ใช้เวลานานหรือซับซ้อนอาจต้องระวังให้มากขึ้น ไม่ว่าในกรณีใดมันเป็นนิสัยที่ดีในการปิดไฟล์ของคุณ
Russell Borogove

3
@agf: ถูกต้องที่ไฟล์ไม่ได้อยู่นอกขอบเขต แต่ไม่เกี่ยวข้องกับความแตกต่างระหว่างforบล็อกและฟังก์ชัน / คลาส / โมดูล มันง่ายกว่านั้นมาก: วัตถุไม่มีขอบเขตเพียงชื่อเท่านั้น ไม่มีชื่อที่อ้างถึงวัตถุนี้ดังนั้นจึงไม่มีอะไรให้อยู่ในขอบเขตหรืออยู่นอกขอบเขต
สูงสุด

@max ความคิดเห็นของฉันแก้ไขข้อสันนิษฐานของเขาว่ามีขอบเขตที่เกี่ยวข้องกับforลูปและกล่าวถึงว่าไฟล์ถูกปิดด้วยเหตุผลที่ต่างออกไปโดยสิ้นเชิง มันไม่เข้ากับขอบเขตใดใน Python เนื่องจากไม่เกี่ยวข้องกับที่นี่
agf

@max มีการอ้างอิงโดยนัยที่กำหนดขอบเขตสำหรับลูป ... นี่คืออาร์กิวเมนต์ของซีแมนทิกส์
Peter R

คำตอบ:


126

ในตัวอย่างของคุณไม่มีการรับประกันว่าไฟล์จะปิดก่อนที่ล่ามจะออก ในเวอร์ชันปัจจุบันของ CPython ไฟล์จะถูกปิดที่ส่วนท้ายของ for loop เนื่องจาก CPython ใช้การนับการอ้างอิงเป็นกลไกการรวบรวมขยะหลัก แต่นั่นคือรายละเอียดการใช้งานไม่ใช่คุณลักษณะของภาษา การใช้งานอื่น ๆ ของ Python ไม่รับประกันว่าจะทำงานได้ ตัวอย่างเช่น IronPython, PyPy และ Jython ไม่ได้ใช้การนับการอ้างอิงดังนั้นจะไม่ปิดไฟล์ในตอนท้ายของลูป

เป็นการปฏิบัติที่ไม่ถูกต้องในการใช้งานการรวบรวมขยะของ CPython เพราะจะทำให้รหัสของคุณพกพาได้น้อยลง คุณอาจไม่มีการรั่วไหลของทรัพยากรถ้าคุณใช้ CPython แต่ถ้าคุณเคยเปลี่ยนไปใช้การใช้งาน Python ที่ไม่ได้ใช้การอ้างอิงอ้างอิงคุณจะต้องผ่านรหัสทั้งหมดของคุณและตรวจสอบให้แน่ใจว่าไฟล์ทั้งหมดของคุณปิดอย่างถูกต้อง

สำหรับตัวอย่างของคุณใช้:

with open("filename") as f:
     for line in f:
        # ... do stuff ...

8
การใช้with open() as fปิดไฟล์โดยอัตโนมัติหลังจากทำเสร็จหรือไม่
Rohan

25
@ Rohan ใช่นั่นคือเวทย์มนตร์เล็ก ๆ ที่withคำแถลงให้ แต่แน่นอนว่าสำหรับเวทย์มนตร์นี้ในการทำงานวัตถุจะต้องมีวิธีการเฉพาะ__enter__และ__exit__ในตอนหลังวัตถุจะทำcloseและสิ่งอื่น ๆ ที่ต้องทำความสะอาดที่ ในตอนท้ายของwithคำสั่ง ...
Copperfield

1
FYI: คำตอบนี้จะอธิบายเฉพาะ "เมื่อจะปิด" แต่ไม่ได้อธิบายว่า "จะเกิดอะไรขึ้นถ้าเปิดอยู่" สำหรับหลังโปรดอ่าน "จะเกิดอะไรขึ้นหากไฟล์เปิดอยู่" มีส่วนร่วมในคำตอบนี้ ( askubuntu.com/questions/701491/… )
RayLuo

ยิ่งกว่านั้นการไม่ปิดไฟล์อาจส่งผลให้ไฟล์ถูกตัดทอนเนื่องจากเนื้อหาไฟล์ยังไม่ถูกลบทิ้ง
Erwan Legrand

ดังนั้นหากฉันไม่ปิดไฟล์ฉันจะได้รับหน่วยความจำของฉันกลับมาอย่างแน่นอนเมื่อโปรแกรมหยุดทำงานหรือไม่ หรือฉันต้องลาออกจากล่ามทั้งหมดหรือไม่
Pro Q

22

Pythons บางตัวจะปิดไฟล์โดยอัตโนมัติเมื่อไม่มีการอ้างอิงอีกต่อไปในขณะที่คนอื่นจะไม่เปิดและมันก็ขึ้นอยู่กับ O / S เพื่อปิดไฟล์เมื่อ Python interpreter ออก

แม้สำหรับ Pythons ที่จะปิดไฟล์ให้คุณ แต่ก็ไม่รับประกันเวลา: อาจเป็นได้ทันทีหรืออาจเป็นวินาที / นาที / ชั่วโมง / วันต่อมา

ดังนั้นในขณะที่คุณอาจไม่ประสบปัญหากับ Python ที่คุณใช้อยู่มันก็ไม่ควรเปิดไฟล์ทิ้งไว้ อันที่จริงใน cpython 3 คุณจะได้รับคำเตือนว่าระบบจะต้องปิดไฟล์ให้คุณหากคุณไม่ได้ทำ

คุณธรรม: ทำความสะอาดหลังจากที่ตัวเอง :)


9
ไฟล์ถูกปิดเมื่อไม่ได้อ้างอิงใน CPython อีกต่อไป แต่นั่นไม่ใช่คุณลักษณะภาษา ถ้าเป็นเช่นนั้นคุณสามารถพึ่งพามันได้อย่างมีความสุข
ปีเตอร์เกรแฮม

9

แม้ว่ามันจะค่อนข้างปลอดภัยที่จะใช้โครงสร้างดังกล่าวในกรณีนี้โดยเฉพาะ แต่มีข้อแม้บางประการสำหรับสรุปการปฏิบัติดังกล่าว:

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

3

ไฟล์ได้รับการรวบรวมขยะและด้วยเหตุนี้จึงปิด GC กำหนดเวลาที่จะปิดไม่ใช่คุณ เห็นได้ชัดว่านี่ไม่ใช่วิธีปฏิบัติที่แนะนำเนื่องจากคุณอาจถึงขีด จำกัด การจัดการไฟล์แบบเปิดหากคุณไม่ปิดไฟล์ทันทีที่คุณใช้งานเสร็จ ถ้าภายในforลูปของคุณคุณเปิดไฟล์มากขึ้นและปล่อยให้มันค้างอยู่?


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

1
ใน CPython การนับการอ้างอิงจะทำให้เกิดการรวบรวมหลังจากforคำสั่ง - คุณไม่ต้องรอการเรียกเก็บขยะครั้งต่อไป
agf

3

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

ดังนั้นสมมติว่าคุณมีสถานการณ์ที่คุณเขียนเนื้อหาไปยังไฟล์ใหม่แล้วโดยไม่ต้องปิด fd คุณกำลังใช้ไฟล์นั้น (ไม่ใช่ fd) ในคำสั่งเชลล์อื่นซึ่งอ่านเนื้อหาของมัน ในสถานการณ์เช่นนี้คุณจะไม่ได้รับเนื้อหาของคำสั่งเชลล์ตามที่คาดไว้และหากคุณพยายามที่จะทำการดีบั๊กคุณจะไม่สามารถค้นหาบั๊กได้ง่าย คุณสามารถอ่านเพิ่มเติมในรายการบล็อกของฉันได้ที่http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html


1

ในระหว่างกระบวนการ I / O ข้อมูลจะถูกบัฟเฟอร์: ซึ่งหมายความว่ามันถูกเก็บไว้ในตำแหน่งชั่วคราวก่อนที่จะถูกเขียนลงในไฟล์

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

หากคุณเขียนไปยังไฟล์โดยไม่ปิดข้อมูลจะไม่ทำให้เป็นไฟล์เป้าหมาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.