25

この質問は何についてではありません

この質問は、File#closeまたはFile#openブロック構文を使用してファイルを自動閉じる方法に関するものではありません。これは、Rubyが実行時に開いているファイル記述子のリストをどこに保存するかについての質問です。

実際の質問

開いている記述子を持つプログラムがあるが、関連するファイルまたはIOオブジェクトにアクセスできない場合、現在開いているファイル記述子への参照をどのように見つけることができますか?この例を見てください:

filename='/tmp/foo'
%x( touch "#{filename}" )
File.open(filename)
filehandle = File.open(filename)

最初のFileインスタンスが開かれますが、オブジェクトへの参照は変数に格納されません。2番目のインスタンスはfilehandleに格納されており、#inspectまたは#closeを使用して簡単にアクセスできます。

ただし、破棄されたFileオブジェクトはなくなりません。明白な方法でアクセスできないだけです。オブジェクトが完成するまで、Rubyはどこかでそれを追跡している必要があります...しかしどこで?

4

1 に答える 1

39

TL; DR

すべてのファイルおよびIOオブジェクトはObjectSpaceに保存されます。

答え

ObjectSpaceクラスは次のように述べています。

ObjectSpaceモジュールには、ガベージコレクション機能と対話し、イテレータを使用してすべての生きているオブジェクトをトラバースできるようにする多数のルーチンが含まれています。

これをどのようにテストしたか

これをRuby1.9.3p194のコンソールでテストしました。

テストフィクスチャは本当に簡単です。アイデアは、異なるオブジェクトIDを持つ2つのFileオブジェクトを持つことですが、変数を介して直接アクセスできるのは1つだけです。もう1つは「どこかにある」です。

# Don't save a reference to the first object.
filename='/tmp/foo'
File.open(filename)
filehandle = File.open(filename)

次に、明示的なオブジェクト参照を使用しなくても、Fileオブジェクトを操作するさまざまな方法を検討しました。ObjectSpaceについて知ったら、これは驚くほど簡単でした。

# List all open File objects.
ObjectSpace.each_object(File) do |f|
  puts "%s: %d" % [f.path, f.fileno] unless f.closed?
end

# List the "dangling" File object which we didn't store in a variable.
ObjectSpace.each_object(File) do |f|
  unless f.closed?  
    printf "%s: %d\n", f.path, f.fileno unless f === filehandle
  end
end

# Close any dangling File objects. Ignore already-closed files, and leave
# the "accessible" object stored in *filehandle* alone.
ObjectSpace.each_object(File) {|f| f.close unless f === filehandle rescue nil}

結論

これを行う他の方法があるかもしれませんが、これは私が自分のかゆみを掻くために思いついた答えです。より良い方法を知っている場合は、別の回答を投稿してください。世界はそれにとってより良い場所になるでしょう。

于 2012-06-06T20:48:39.747 に答える