RubyのFile.openのブロックによるリソース管理について

File.openのリソース管理について調べてみた。

コードをためす

次のように,いくつかのファイルをそれぞれ異なった書き方で開いてみる:

f1 = f2 = f3 = f4 = f5 = ''
#open 1
File.open('test.txt'){|f1|
  puts f1.read
  #open 2
  f2 = File.open('test2.txt')
  puts f2.read
  #open 3
  f3 = File.open('test3.txt').each do |l|
    puts l
  end
  #open 4
  (f4 = File.open('test4.txt').each do |l|
    puts l
   end).close
  #open 5
  File.open('test5.txt'){|f5|
    f5.read
  }.each{|l|
    puts l
  }
}
p f1 #=> #<File:test.txt (closed)>
p f2 #=> #<File:test2.txt>
p f3 #=> #<File:test3.txt>
p f4 #=> #<File:test4.txt (closed)>
p f5 #=> #<File:test5.txt (closed)>
一番目のファイル test.txt

close される。
これは一番忠実な書き方で,閉じているのは明白かな。

二番目のファイル test2.txt

close されない。
一番目のファイルを開いた File.open のブロックの中で開いたけど,これは閉じてくれない。

三番目のファイル test3.txt

close されない。
一見 close されるように見えるんだけど,each にブロックを渡していて Fire.open にはブロックを渡していないので閉じてくれない。

四番目のファイル test4.txt

close される。
each は self(つまりファイルオブジェクト)を返すから end の後に close を書けば,手動でファイルを閉じたことになる。

五番目のファイル test5.txt

close される。
メソッドチェーンしてみた。一番目と同様,Fire.open にブロックを渡しているので閉じる。Fire.open はブロックを渡されるとブロックの最後の値を返すようだから,こんな書き方ができる。

まとめ

つまり,File.openが自動でリソースを管理してくれるのは,File.open にブロックを渡したときだけみたい。

というかリファレンスにそう書いてあった:

open() はブロックを指定することができます。
ブロックを指定して呼び出した場合は、ファイルオブジェクトを
与えられてブロックが実行されます。ブロックの実行が終了すると、
ファイルは自動的にクローズされます。
解る人にはこれで十分だろうけど,解らない人が見たらこれじゃ解らないよ^^;