ham-capのブログ

プログラミング学習の記録

【Ruby】ファイルの詳細な情報をまとめてゲットするゾ

したいこと

特定のファイルの詳細な情報(ファイルのサイズ・タイプ・オーナーのユーザID等)を取得したい。 ※以下、この記事内でファイルという言葉を使う場合は基本的にディレクトリも含んでいます。

File::Statクラス

あるファイルの詳細情報を取得したいときにはFile::statクラスを使うと便利です。以下、リファレンスマニュアルによる説明です。

ファイルの情報を格納したオブジェクトのクラス。 FileTest に同名のモジュール関数がある場合はそれと同じ働きをします。ただ、ファイル名を引数に取るかわりに Stat 自身について判定する点が違います。

docs.ruby-lang.org

はい。後半のモジュール関数がどうのこうのというのは正直僕もよくわかっていませんが、今回はそこはそんなに重要じゃない(と思う)ので深くつっこみません。

重要なのはFile::Statクラスのオブジェクトはファイルの情報を格納できるということです。(そのまんま)

このクラスのインスタンスメソッドの多くはそのオブジェクトの特定の情報を返してくれるものなので、それらのメソッドを使用して自分の欲しい情報を取得するという使い方になります。

例えば、あるファイルのサイズを知りたい場合はsizeメソッドを用いて以下のような書き方ができます。

file = File.stat("hoge")
file.size

statメソッドの引数には情報を取得する対象となるファイルのファイル名を渡します。 この場合、変数fileにはhogeというファイルの各種情報がまとめて格納されていて、その中からファイルサイズの情報をsizeメソッドを使用して取り出しているということになります。

初めてこのクラスを使ったときに個人的にちょっと面白かったのは、File::Statクラスのオブジェクトを作成する際にはFileクラスのstatメソッドを使用するということ。なるほど。クラス名が::でつながっている理由が何となくわかった気がします。 実際にはFile::Stat.newでも作成できますが、そこはかとなくもっちゃりしてませんか?(個人の感想です)

Dir.globと組み合わせる

さて、File::Statクラスを使ってファイルの詳細情報をゲットする方法は以上なのですが、それだけだと面白くないので僕が実際にやった具体的な使い方を紹介します。

僕がこのFile::Statを使う必要があったのは、カレントディレクトリにある全ファイルの情報を取得したかったからです。 そこで使用したのが、このブログの前々回の記事でご紹介したDir.globとの組み合わせです。 File.statを使用する際の引数は対象となるファイルのファイル名です。そしてDir.globはファイル名を取得するためのメソッドです。

もう大体わかると思いますが、要はDir.globでファイル名を取得して、それをそのままFile.statの引数として渡してしまえば、それらのファイル全ての詳細情報を取得できるということです。

というわけで、僕が実際に書いたのはこんな感じです。

file_names = Dir.glob("*")
files = []
file_names.each do |name|
  files << File.stat(name)
end

これでカレントディレクトリの全てのファイル情報が取得できました。(今回は隠しファイルは含めていません。)

流れとしては、

  1. Dir.globでファイル名を取得
  2. filesという空の配列を用意
  3. eachによる繰り返し処理で配列filesFile::Statオブジェクトを順番に入れていく

となります。 この配列から任意のファイルの特定の情報を取り出す場合、

files[0].size

のように、インデックスでどのオブジェクトか指定したうえでメソッドを使用します。

トラップ

非常に便利なこのFile::Statですが、1点注意があります。

それはFile::Statが格納している情報にはファイル名が含まれていないということ。 これほんとトラップだと思います。 だってよく考えてください。 ここまでの流れからして、

file = File.stat("hoge")
file.name

こんなふうにすればhogeって取得できそうなもんじゃないですか。 でもダメなんです。いくら引数でファイル名を渡していようとそれはそれ、これはこれです(?)

まるで「あなたもうファイル名は知ってるじゃない。私がなんで教えてあげなきゃいけないの?」と意地悪されているような気分になります。

ほんとに謎仕様。

なので、ファイル名は別の変数で用意するか、1つのオブジェクトに入れてしまいたい場合は新しくクラスを定義するのがいいと思います。僕は後者の方法で使用しました。

というわけで、今回はこんな感じです。

記載内容に間違い等があった場合にはこっそり教えていただければ幸いです。 最後までお読みいただきありがとうございました。