RubyのFile.openとf.closeの必要性


92

ほとんどのプログラミング言語では、ファイルを操作するためのフローがopen-use-closeであることが一般的です。それでもルビーコードで比類のないFile.open呼び出しを何度も目にし、さらにルビードキュメントでこの知識の宝石を見つけました:

I / Oストリームは、ガベージコレクターによって要求されたときに自動的に閉じられます。

darkredandyellowフレンドリーircが問題を引き受けます:
[17:12]はい、また、ファイル記述子の数は通常OSによって制限されます
[17:29] ガベージコレクターがクリーンアップする前に、利用可能なファイル記述子が簡単に不足する可能性があると思いますアップ。この場合、自分で閉じて使用することをお勧めします。「ガベージコレクターによって要求されました。」GCが将来のある時点で機能することを意味します。そしてそれは高価です。ファイルを明示的に閉じる多くの理由。

  1. 明示的に閉じる必要がありますか
  2. はいの場合、なぜGCは自動的に閉じますか?
  3. そうでない場合、なぜオプションですか?

1
デストラクタが発明されて以来、「常識」は古くなっています。
貧弱

1
@meager:デストラクタが発明されたのはいつですか?
Andrew Grimm

注:ファイル記述子は制限されていますが、少なくともLinuxでは、その制限は非常に高くなっています。
Linuxios、2013年

1
@Linuxios:私のubuntu12.04 $ ulimit -n => 1024では、単純な仕事をしているときだけ高いです。悪い癖はいつか大きな問題を引き起こすでしょう!
2013年

回答:


133

Rubyコードで比類のないFile.open呼び出しを何度も見ました

例を挙げていただけますか?「ほとんどのプログラミング言語で、ファイルを操作するためのフローがopen-use-closeであるという一般的な知識」を欠いている初心者によって書かれたコードでは、これだけしか目にしません。

経験豊富なRubyistは、ファイルを明示的に閉じるか、またはより慣用的に、のブロック形式を使用し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クラスがファイルを閉じるファイナライザを定義していることが起こります。

そうでない場合、なぜオプションですか?

無駄なメモリは安いですが、無駄なファイル記述子はそうではありません。したがって、ファイル記述子の存続期間をメモリのチャンクの存続期間に関連付けることは意味がありません。

あなたは、単に予測できないとき、ガベージコレクタが実行されます。あなたも予測することができないならば、それは実行されるすべてで:あなたはメモリが不足したことがない場合は、ガベージコレクタが実行されることはありません、したがって、ファイナライザが実行されることはありませんので、ファイルを閉じことはありません。


1
github.com/isaac/sunspot/blob/cell/sunspot/lib/sunspot/…+23(Kernel#openであり、主にHTTP側で使用されますが、それでもローカルファイルパスパラメーターで到達しました。 ..;私はまだpatch&request-pullする時間を見つけようとしています)、github.com / jnicklas / carrierwave Ctrl + f "File.open"(それは例として与えられていますが、悪い方法で...)、そしていくつか覚えていない他の場所。ため、私は私のプロジェクトでの安定性要件の問題と牛肉..持っている
clyfe

3
この例では、レイズはレスキューブロック内にある必要がありますか?raiseが呼び出され、例外がない場合、これは実行時エラーをスローするだけではありませんか?
Jeff Storey

@JeffStorey:いいキャッチ!17ヶ月...見過ごさ
イェルクWミッターク

@JörgWMittagと今からあと17か月は修正されていません:PIはここでの主なポイントはensurerescueありraise、まったく必要ないことを推測します。
KL-7

私はあなたが持っていないことができると思いensureなしrescue。そして、あなたはただ黙って例外を飲み込むだけではなく、ファイルを閉じた後にそれを呼び出し元に伝播する必要があります。とにかく、月に再び'15 :-D私を思い出させる
イェルクWミッターク

71

使用後は常にファイル記述子をクローズする必要があります。これにより、ファイル記述子もフラッシュされます。多くの場合、ファイル記述子の有効期間を処理するために、ブロックでFile.openまたは同等のメソッドを使用します。例えば:

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

その例では、ファイルは自動的に閉じられます。


いい視点ね。File.closeを呼び出さないスクリプトのバグを追跡しました。結果として、一部のファイルでは最後の行が欠落することがあります。
Erwan Legrand 2016年

未解決の。私はこのトリックを知りませんでした。その点では、java-8によく似ています。ありがとうございました。
サグネタ2016年

2

http://ruby-doc.org/core-2.1.4/File.html#method-c-openによると

関連するブロックがない場合、File.openは:: newの同義語です。オプションのコードブロックを指定すると、開いているファイルが引数として渡され、ブロックが終了するとFileオブジェクトが自動的に閉じます。ブロックの値はFile.openから返されます。

したがって、ブロックが終了すると自動的に閉じられます:D


1
  1. はい
  2. そうしない場合、またはその他の障害がある場合
  3. 2を参照してください。

-3

File.read()関数を使用して、ruby .....などのファイルを読み取ることができます。

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

この例でfile_variableは、そのファイルの完全な値を保持できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.