Ruby's File.open và nhu cầu về f.close


92

Thông thường trong hầu hết các ngôn ngữ lập trình, quy trình làm việc với tệp là mở-sử dụng-đóng. Tuy nhiên, tôi đã thấy nhiều lần trong mã ruby ​​các lệnh gọi File.open chưa từng có và hơn thế nữa, tôi đã tìm thấy viên ngọc tri thức này trong tài liệu về ruby:

Các luồng I / O tự động đóng khi chúng được bộ thu gom rác xác nhận.

darkredandyellow thân thiện với vấn đề:
[17:12] vâng, ngoài ra, số lượng bộ mô tả tệp thường bị giới hạn bởi hệ điều hành
[17:29] Tôi cho rằng bạn có thể dễ dàng sử dụng hết bộ mô tả tệp có sẵn trước khi bộ thu gom rác dọn dẹp lên. trong trường hợp này, bạn có thể muốn tự mình đóng chúng. "do người thu gom rác yêu cầu." nghĩa là Tổng công ty hành động vào một thời điểm nào đó trong tương lai. và nó đắt. rất nhiều lý do để đóng tệp một cách rõ ràng.

  1. Chúng ta có cần phải đóng một cách rõ ràng không
  2. Nếu có thì tại sao GC tự động đóng?
  3. Nếu không thì tại sao tùy chọn?

1
'Kiến thức chung' của bạn đã lỗi thời kể từ khi các trình hủy được phát minh.
Mudgar

1
@meager: Máy hủy được phát minh khi nào?
Andrew Grimm,

Chỉ cần lưu ý: Mặc dù trình mô tả tệp bị hạn chế, nhưng ít nhất trên Linux, giới hạn này khá cao.
Linuxios

1
@Linuxios: trên ubuntu12.04 của tôi, $ ulimit -n => 1024nó chỉ cao khi bạn chỉ làm một số công việc đơn giản. Thói quen xấu một ngày nào đó sẽ gây ra vấn đề lớn!
HVNSweeting

Câu trả lời:


133

Tôi đã thấy nhiều lần trong các File.opencuộc gọi chưa từng có mã ruby

Bạn có thể đưa ra một ví dụ không? Tôi chỉ thấy rằng trong mã được viết bởi những người mới thiếu "kiến thức phổ biến trong hầu hết các ngôn ngữ lập trình rằng quy trình làm việc với các tệp là mở-sử dụng-đóng".

Các Rubyists có kinh nghiệm hoặc đóng tệp của họ một cách rõ ràng, hoặc nói một cách dễ hiểu hơn, sử dụng biểu mẫu khối File.openđể tự động đóng tệp cho bạn. Việc triển khai của nó về cơ bản trông giống như sau:

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

Tập lệnh là một trường hợp đặc biệt. Các tập lệnh thường chạy quá ngắn và sử dụng quá ít bộ mô tả tệp nên việc đóng chúng chỉ đơn giản là không hợp lý, vì hệ điều hành sẽ đóng chúng lại khi tập lệnh thoát.

Chúng ta có cần phải đóng một cách rõ ràng không?

Đúng.

Nếu có thì tại sao GC tự động đóng?

Bởi vì sau khi nó đã thu thập đối tượng, không có cách nào để bạn đóng tệp nữa, và do đó bạn sẽ làm rò rỉ các bộ mô tả tệp.

Lưu ý rằng nó không phải là trình thu gom rác đóng các tệp. Bộ thu gom rác chỉ đơn giản là thực thi bất kỳ trình hoàn thiện nào cho một đối tượng trước khi nó thu thập nó. Nó chỉ xảy ra khi Filelớp xác định một trình hoàn thiện đóng tệp.

Nếu không thì tại sao tùy chọn?

Bởi vì bộ nhớ lãng phí là rẻ, nhưng bộ mô tả tệp lãng phí thì không. Do đó, không có ý nghĩa gì khi buộc thời gian tồn tại của bộ mô tả tệp với thời gian tồn tại của một số đoạn bộ nhớ.

Bạn chỉ đơn giản là không thể dự đoán khi nào trình thu gom rác sẽ chạy. Bạn thậm chí không thể đoán được liệu nó có chạy hết hay không : nếu bạn không bao giờ hết bộ nhớ, trình thu gom rác sẽ không bao giờ chạy, do đó trình hoàn thiện sẽ không bao giờ chạy, do đó tệp sẽ không bao giờ bị đóng.


1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/… +23 (mặc dù Kernel # của nó mở và được sử dụng chủ yếu cho phía HTTP của nó, nhưng tôi đã truy cập nó bằng tham số đường dẫn tệp cục bộ, tuy nhiên. ..; Tôi vẫn đang cố gắng tìm thời gian để vá & request-pull), github.com/jnicklas/carrierwave Ctrl + f "File.open" (nó được đưa ra làm ví dụ, nhưng theo cách xấu ...) và một số những nơi khác tôi không nhớ. Tôi rất
lo lắng

3
Trong ví dụ này, có nên tăng bên trong khối cứu hộ không? Điều này sẽ không chỉ gây ra lỗi thời gian chạy nếu lệnh tăng được gọi và không có ngoại lệ?
Jeff Storey

@JeffStorey: bắt rất hay! 17 tháng không được chú ý…
Jörg W Mittag

@ JörgWMittag và bây giờ là 17 tháng nữa không cố định: PI đoán điểm chính ở đây là ensure, rescueraisekhông cần thiết chút nào.
KL-7 ngày 7

Tôi nghĩ rằng bạn không thể có ensuremà không có rescue. Và bạn không thể chỉ âm thầm nuốt ngoại lệ, bạn cần phải tuyên truyền nó cho người gọi, sau khi đã đóng tệp. Dù sao, hãy nhắc tôi một lần nữa vào tháng Năm '15 :-D
Jörg W Mittag

71

Bạn nên luôn đóng các bộ mô tả tệp sau khi sử dụng, điều này cũng sẽ xóa nó. Thường thì mọi người sử dụng File.open hoặc phương thức tương đương với các khối để xử lý thời gian tồn tại của bộ mô tả tệp. Ví dụ:

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

Trong ví dụ đó, tệp được đóng tự động.


Điểm tốt. Tôi đã theo dõi một lỗi đối với một tập lệnh không gọi là File.close. Do đó, dòng cuối cùng sẽ bị thiếu trong một số tệp bây giờ và sau đó.
Erwan Legrand

Nổi bật. Tôi chưa bao giờ biết thủ thuật này. Giống như java-8 về mặt đó. Cảm ơn bạn.
sagneta

2

Theo http://ruby-doc.org/core-2.1.4/File.html#method-c-open

Không có khối liên kết, File.open là một từ đồng nghĩa với :: new. Nếu khối mã tùy chọn được đưa ra, nó sẽ được chuyển sang tệp đã mở làm đối số và đối tượng Tệp sẽ tự động bị đóng khi khối kết thúc. Giá trị của khối sẽ được trả về từ File.open.

Do đó, sẽ tự động bị đóng khi khối kết thúc : D


1
  1. Đúng
  2. Trong trường hợp bạn không, hoặc nếu có một số lỗi khác
  3. Xem 2.

-3

Chúng ta có thể sử dụng File.read()chức năng để đọc tệp trong ruby ​​..... chẳng hạn như,

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

trong ví dụ này file_variablecó thể có giá trị đầy đủ của tệp đó ....

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.