เปิดไฟล์ของรูบี้และความต้องการ f.close


92

เป็นความรู้ทั่วไปในภาษาโปรแกรมส่วนใหญ่ที่โฟลว์สำหรับการทำงานกับไฟล์เป็นแบบเปิดใช้ - ปิด แต่ฉันเห็นหลายครั้งในรหัสทับทิมที่ไม่ตรงกันการโทร File.open และยิ่งไปกว่านั้นฉันพบอัญมณีแห่งความรู้นี้ในเอกสารทับทิม:

สตรีม I / O จะปิดโดยอัตโนมัติเมื่อมีการอ้างสิทธิ์โดยตัวรวบรวมขยะ

darkredandyellow irc เป็นมิตรกับปัญหา:
[17:12] ใช่และจำนวนตัวอธิบายไฟล์มักจะถูก จำกัด โดยระบบปฏิบัติการ
[17:29] ฉันคิดว่าคุณสามารถใช้ตัวอธิบายไฟล์ที่มีอยู่หมดได้อย่างง่ายดายก่อนที่ตัวเก็บขยะจะทำความสะอาด ขึ้น. ในกรณีนี้คุณอาจต้องการปิดด้วยตัวเอง "อ้างโดยคนเก็บขยะ" หมายความว่า GC จะทำหน้าที่ในอนาคต และมันแพง สาเหตุหลายประการในการปิดไฟล์อย่างชัดเจน

  1. เราจำเป็นต้องปิดอย่างชัดเจนหรือไม่
  2. ถ้าใช่ทำไม GC จึงปิดอัตโนมัติ
  3. ถ้าไม่แล้วทำไมตัวเลือก?

1
'ความรู้ทั่วไป' ของคุณล้าสมัยไปแล้วตั้งแต่มีการคิดค้นผู้ทำลายล้าง
meagar

1
@meager: ผู้ทำลายถูกคิดค้นขึ้นเมื่อใด?
Andrew Grimm

หมายเหตุ: ในขณะที่ตัวอธิบายไฟล์มี จำกัด แต่อย่างน้อยบน Linux ขีด จำกัด ก็ค่อนข้างสูง
Linuxios

1
@Linuxios: บน ubuntu12.04 ของฉัน$ ulimit -n => 1024มันสูงก็ต่อเมื่อคุณทำงานง่ายๆ นิสัยไม่ดีจะทำให้เกิดปัญหาใหญ่ในวันหนึ่ง!
HVNSweeting

คำตอบ:


133

ผมเห็นหลายครั้งในรหัสทับทิมเปรียบFile.openโทร

คุณสามารถยกตัวอย่างได้หรือไม่? ฉันเคยเห็นว่าในโค้ดที่เขียนโดยมือใหม่ที่ขาด "ความรู้ทั่วไปในภาษาโปรแกรมส่วนใหญ่ที่โฟลว์สำหรับการทำงานกับไฟล์เป็นแบบเปิด - ใช้ - ปิด"

Rubyists ที่มีประสบการณ์อาจปิดไฟล์ของตนอย่างชัดเจนหรือใช้รูปแบบการบล็อกFile.openซึ่งจะปิดไฟล์ให้คุณโดยอัตโนมัติ การใช้งานโดยทั่วไปมีลักษณะดังนี้:

def File.open(*args, &block)
  return open_with_block(*args, &block) if block_given?
  open_without_block(*args)
end

def File.open_without_block(*args)
  # do whatever ...
end

def File.open_with_block(*args)
  yield f = open_without_block(*args)
ensure
  f.close
end

สคริปต์เป็นกรณีพิเศษ โดยทั่วไปสคริปต์จะทำงานสั้น ๆ และใช้ตัวอธิบายไฟล์เพียงไม่กี่ตัวจึงไม่สมเหตุสมผลที่จะปิดเนื่องจากระบบปฏิบัติการจะปิดมันต่อไปเมื่อสคริปต์ออก

เราจำเป็นต้องปิดอย่างชัดเจนหรือไม่?

ใช่.

ถ้าใช่เหตุใด GC จึงปิดอัตโนมัติ

เนื่องจากหลังจากรวบรวมวัตถุแล้วจะไม่มีทางที่คุณจะปิดไฟล์ได้อีกต่อไปดังนั้นคุณจะทำให้ตัวอธิบายไฟล์รั่วไหล

โปรดทราบว่าไม่ใช่ตัวรวบรวมขยะที่ปิดไฟล์ ตัวเก็บขยะจะดำเนินการขั้นสุดท้ายของอ็อบเจ็กต์ก่อนที่จะรวบรวม มันเกิดขึ้นที่Fileคลาสกำหนด Finalizer ซึ่งจะปิดไฟล์

ถ้าไม่แล้วทำไมตัวเลือก?

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

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


1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/… +23 (แม้ว่า Kernel # จะเปิดและใช้เป็นหลักสำหรับฝั่ง HTTP แต่ฉันเข้าถึงได้ด้วยพารามิเตอร์เส้นทางไฟล์ในเครื่องอย่างไรก็ตาม .. ; ฉันยังคงพยายามหาเวลาแก้ไข & request-pull), github.com/jnicklas/carrierwave Ctrl + f "File.open" (เป็นตัวอย่าง แต่ในทางที่ไม่ดี ... ) และอีกหลาย ๆ สถานที่อื่น ๆ ฉันจำไม่ได้ ฉันมีปัญหาเนื่องจากข้อกำหนดด้านความมั่นคงในโครงการของฉัน ..
clyfe

3
ในตัวอย่างนี้การเพิ่มควรอยู่ในบล็อกช่วยเหลือหรือไม่? สิ่งนี้จะไม่ทำให้เกิดข้อผิดพลาดรันไทม์หากมีการเรียกเพิ่มและไม่มีข้อยกเว้น?
Jeff Storey

@JeffStorey: จับดี! 17 เดือนไม่มีใครสังเกตเห็น…
Jörg W Mittag

@ JörgWMittagและตอนนี้ 17 เดือนขึ้นไปไม่คงที่: PI เดาจุดหลักที่นี่คือensure, rescueและraiseไม่จำเป็นที่ทุกคน
KL-7

ฉันคิดว่าคุณไม่สามารถมีได้โดยไม่ต้องensure rescueและคุณไม่สามารถกลืนข้อยกเว้นแบบเงียบ ๆ ได้คุณต้องเผยแพร่ไปยังผู้โทรหลังจากปิดไฟล์แล้ว อย่างไรก็ตามเตือนฉันอีกครั้งในเดือนพฤษภาคม '15 :-D
Jörg W Mittag

72

คุณควรปิด file descriptors ทุกครั้งหลังการใช้งานซึ่งจะล้างออกด้วย บ่อยครั้งที่ผู้คนใช้File.openหรือวิธีการที่เทียบเท่ากับบล็อกเพื่อจัดการอายุการใช้งานตัวอธิบายไฟล์ ตัวอย่างเช่น:

File.open('foo', 'w') do |f|
    f.write "bar"
end

ในตัวอย่างนั้นไฟล์จะปิดโดยอัตโนมัติ


จุดดี. ฉันติดตามจุดบกพร่องของสคริปต์ที่ไม่เรียก File.close ดังนั้นบรรทัดสุดท้ายจะหายไปในบางไฟล์ในตอนนี้
Erwan Legrand

โดดเด่น. ฉันไม่เคยรู้เคล็ดลับนี้ เหมือนกับ java-8 ในเรื่องนั้น ขอบคุณ.
sagneta

2

อ้างอิงจากhttp://ruby-doc.org/core-2.1.4/File.html#method-c-open

หากไม่มีบล็อกที่เกี่ยวข้อง File.open เป็นคำพ้องความหมายของ :: new หากกำหนดรหัสบล็อกที่เป็นทางเลือกบล็อกจะถูกส่งผ่านไฟล์ที่เปิดเป็นอาร์กิวเมนต์และอ็อบเจ็กต์ไฟล์จะถูกปิดโดยอัตโนมัติเมื่อบล็อกสิ้นสุดลง ค่าของบล็อกจะถูกส่งกลับจาก File.open

ดังนั้นจะปิดโดยอัตโนมัติเมื่อบล็อกสิ้นสุด : D



-3

เราสามารถใช้File.read()ฟังก์ชั่นอ่านไฟล์ในรูบี้ ..... เช่น,

file_variable = File.read("filename.txt")

ในตัวอย่างนี้file_variableสามารถมีค่าเต็มของไฟล์นั้น ....

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