Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyのTempfileクラスで一時ファイルを作成・操作する方法を徹底解説

Rubyで一時ファイルを作成すると、OS(オペレーティングシステム)の一時フォルダ内に、ランダムな名前を持つ空のファイルが生成されます。

そして、このファイルは自動的に削除されるのが大きな特徴です。

では、Rubyでこれを実現するにはどうすればよいのでしょうか?

答えはこうです

require 'tempfile'

Tempfile.create { |f| f << "abc\n" }

ここで f がファイルオブジェクトを表し、<< 演算子を使ってファイルに書き込みを行います。

この機能はRubyに標準で組み込まれているため、追加のgemをインストールする必要はありません。

基本的な使い方はシンプルですが、実際に使ってみると疑問がいくつか浮かんでくるかもしれません。

例えば、こんな疑問です

  • 一時ファイルは正確にいつ削除されるのか?
  • なぜ一時ファイルから読み戻しができないのか?
  • 一時ファイル名は本当にユニークであることが保証されているのか?

この記事では、これらの疑問とその他の重要なポイントについて詳しく解説し、Tempfileへの理解を深めていきましょう!

new と create の違いとは?

Tempfile クラスには、ファイルを作成するためのメソッドが2つ用意されています。

ひとつは new、もうひとつは create です。

この2つには何か違いがあるのでしょうか?

公式ドキュメントによると、newTempfile オブジェクトを生成するのに対し、createFile オブジェクトを返します。

ただ、Tempfile は内部で File に処理を委譲(デリゲート)しているため、この違いは実用上それほど重要ではありません。

本当の違いは、create がブロックを受け取れることにあります。

一方、new はブロックを受け付けません。

試しに次のコードを実行してみてください

Tempfile.new {}

すると、こんな警告が表示されます

# warning: Tempfile.new doesn't call the given block.

create をブロック付きで使えば、ブロックが終了した時点で一時ファイルが確実に削除されるようになります。

ここで、次のような疑問が生まれます…

一時ファイルはいつ削除されるのか?

一時ファイルの削除タイミングは、自分で制御することもできます。通常のファイルと同じように delete メソッドで明示的に削除するか、create をブロック付きで呼び出す方法です。

自動削除が行われるのは、以下の場合です

  • プログラムが終了したとき
  • ファイルが「ガベージコレクション」されたとき。つまり、メモリ領域を解放するためにアルゴリズムによってファイルがメモリから取り除かれたとき

後者が起こるのは、ファイルへの参照をどこにも保持していない場合だけです。

たとえば変数などが参照にあたります。

具体例を見てみましょう

t = Tempfile.new

変数 t がスコープ外に出ると、その一時ファイルは削除可能な状態になります。

Linuxをお使いの方なら、リアルタイムでファイルの作成・削除を監視できる inotify-tools という便利なツールがあります。

次のコマンドを試してみてください

inotifywait /tmp -m --format "%w %e %f %T" --timefmt "%H:%m:%S"

その状態で、ファイルを作成するRubyコードを実行します。

実行例

ruby -rtempfile -e "def c; t = Tempfile.new('testing'); end; c; sleep 10"

すると、このような出力が得られます

/tmp/ CREATE testing20190506-11391-1wqcng0 14:51:48
/tmp/ OPEN testing20190506-11391-1wqcng0 14:51:48
/tmp/ CLOSE_WRITE,CLOSE testing20190506-11391-1wqcng0 14:51:58
/tmp/ DELETE testing20190506-11391-1wqcng0 14:51:58

ファイルの作成から削除までの流れを目で確認できるので、理解が深まりますよ。

なぜ一時ファイルから読み戻せないのか?

一時ファイルに書き込んだ内容を読み戻そうとすると、空文字列が返ってきます。

例を見てみましょう

Tempfile.create { |f| f << "abc\n"; f.read }
# ""

これはなぜでしょうか?

実は、File オブジェクトは IO オブジェクトでもあります。

IOオブジェクトは位置ポインタ(カーソル)を持っていて、ファイルに書き込むたびにこのポインタが先頭へ進んでいきます。

そのため、読み込みたい場合はポインタを先頭に巻き戻す必要があるのです。

具体的にはこう書きます

Tempfile.create { |f| f << "abc\n"; f.rewind; f.read }
# "abc\n"

また、状況によってはファイル内容をフラッシュ(強制的に書き出す)必要が出てくることもあります。

temp = Tempfile.new

temp << "1"
temp << "2"

temp.flush

一時ファイル名は本当にユニークなのか?

Tempfileはユニークなファイル名を自動的に生成し、パーミッションモードを600に設定します。これは、そのファイルを作成したユーザーだけが読み取れることを意味します。

では、ファイル名が重複することはあり得るのでしょうか?

公式ドキュメントにはこう記載されています

「Tempfileのファイル名選択メソッドは、スレッドセーフかつプロセス間でも安全です。他のスレッドやプロセスが同じファイル名を選ぶことはありません。」

さらに、new の説明には、ユニークなファイル名が見つけられない場合にはエラーが発生する可能性があるとも書かれています。

また、ファイル名にプレフィックス(接頭辞)を設定できることも覚えておくと便利です。

使い方はこちら

Tempfile.new("banana-").path
# "/tmp/banana-20190426-25403-1cm7sjt"

プレフィックスを付けることで、名前の衝突(コリジョン)が起きる可能性をさらに下げられます。

一時ファイルをバイナリモードで開く方法

画像や音楽ファイルなど、プレーンテキスト以外のデータを扱う場合は、ファイルモードをバイナリに設定したくなるでしょう。

バイナリモードにすると、改行コードの自動変換が無効になります。

その結果、データがより「生(ロウ)」の状態で扱われ、バイナリファイルの一部が壊れてしまうのを防げます。

バイナリモードはデフォルトでは有効になっていません

temp = Tempfile.new

temp.binmode?
# false

有効化するにはこうします

temp = Tempfile.new
temp.binmode

temp.binmode?
# true

create メソッドでも同様に使えます:

Tempfile.create do |f|
  f.binmode

  f << "bacon\n"
end

まとめ

この記事では、Rubyの Tempfile クラスを使った一時ファイルの扱い方について学びました!

基本の作成方法から、削除のタイミング、読み戻しの注意点、ファイル名のユニーク性、バイナリモードまで、実務で役立つポイントを網羅しました。

ぜひご自身のコードで試してみてください。

最後までお読みいただきありがとうございました 🙂

  1. Windows 10で一時ファイルを削除する方法を徹底解説

    PCやデスクトップは、さまざまなファイルを保存できるストレージデバイスとしての役割も果たします。多くのアプリケーションやプログラムがインストールされ、これらのファイルやアプリなどのデータがハードディスクの容量を占めていき、やがてディスク容量が満杯になってしまいます。 ところが、保存しているファイルやアプリの数がそれほど多くないはずなのに、ハードディスクの容量がほぼ満杯と表示されることがあります。新しいファイルやアプリを保存するために空き容量を作ろうとすると、大切なデータまで削除しなければならないことも。なぜこのようなことが起こるのでしょうか? 一時ファイルとは何か 原因は「一時ファイル(テンポ

  2. Windows 11でPDFファイルを作成する方法【印刷機能を使った簡単手順】

    Windowsの際立った機能のひとつが、ドキュメントをPDF形式で「印刷」できることです。PDFは現在、あらゆる印刷ニーズにおける標準フォーマットとなっており、その堅牢性と自由度の高さから、プロフェッショナルな現場でも広く愛用されています。実はMicrosoftはかつて、PDFの対抗馬としてXPS形式の開発に力を注ぎ、「Microsoft XPS Document Writer」をWindowsの標準機能として搭載していました。しかし残念ながらXPSは普及せず、最終的にMicrosoftはPDFへと方針を転換し、「Microsoft Print to PDF(Microsoft PDFへの印刷