【Ruby】File クラスの扱い
概要
Ruby の File クラスで行うファイル操作の基本について書いていきます。
CSV など他のファイルを扱うクラスも存在しますが、基本である File の操作を覚えておくと、
大体のノリは同じなので、覚えることが少なくて済むと思います。
環境
❯ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-darwin21]
ファイル操作の基本
ファイル操作は、多くの場合以下の処理がセットとなります。
- ファイルを開く(または作成する)
- 読み取り、書き込みなどのファイル操作
- ファイルを閉じる
3の「ファイルを閉じる」は忘れがちですが、これをしないとオープンされたファイルが OS 上でリソースを消費し続けることになります。
これが多数のファイルになると、システムのリソースが枯渇します。
長時間実行されるような Web アプリケーションでは、プロセスが終了しない限り、
このリソースが開放されることはないため、パフォーマンスの低下や、リソースの枯渇などの問題が生じます。
そのため、「ファイルは使ったら閉じる」を意識すること。
Ryby では、close
メソッドが、ファイルを閉じる役割をします。
new
File.new では、新しい File オブジェクトを作成します。
これにより、ファイル操作を行うためのオブジェクトが提供されます。
第一引数にファイルのパス、第二引数でモード(読み取り、書き込み)を選択できます。
# 読み取りモードでオブジェクトを作成
file = File.new("./sample_file", "r")
# file.read などのファイル操作
file.close
# 書き込みモードでオブジェクトを作成
file = File.new("./sample_file", "w")
# file.write などのファイル操作
file.close
r
モードを指定して、存在しないファイルを指定すると「そんなファイルがないと」怒られます。
> File.new("./hogehoge", "r")
(irb):16:in `initialize': No such file or directory @ rb_sysopen - ./hogehoge (Errno::ENOENT)
ちなみに w
モードで存在しないファイルを指定すると、そのファイルが作成されます。
open
File.open では、ファイルを開いて操作するためのオブジェクトを作成します。
new のときと同じく、第一引数にファイルのパス、第二引数でモード(読み取り、書き込み)を選択できます。
# 読み取りモードで開かれた状態のオブジェクトを作成
file = File.open("./sample_file", "r")
# file.read などのファイル操作
file.close
# 読み取りモードで開かれた状態のオブジェクトを作成
file = File.open("./sample_file", "w")
# file.write などのファイル操作
file.close
new メソッドとの違いは、引数にブロックを渡せるということです。
ブロックを渡すと、明示的に close をしなくても良くなるため、実際にはこちらを使うことが多いです。
File.open("sample_file", "r") do |file|
# file.read などのファイル操作
end
File.open("sample_file", "w") do |file|
# file.write などのファイル操作
end
read
File.read はその名の通り、指定したファイルの内容を取得します。
例えば以下のようなファイルの場合。
こんにちは
ありがとうございます
これからもよろしくお願いします
結果は以下になります。
> File.read("./sample_file")
=> "こんにちは\nありがとうございます\n\nこれからもよろしくお願いします\n"
delete
File.delete は指定したファイルを削除します。
ユースケース別の操作の紹介
ファイルを新規作成し、書き込み
File.open("sample_file", "w") do |file|
file.write("1行目\n")
file.write("2行目\n")
file.write("3行目\n")
end
# または
File.open("sample_file", "w") do |file|
file.puts("1行目")
file.puts("2行目")
file.puts("3行目")
end
作成されたファイル
1行目
2行目
3行目
既存のファイルを読み込み
ファイル全体を読み込み
> File.read("./sample_file")
=> "1行目\n2行目\n3行目\n"
# または
File.open("sample_file", "r") do |file|
file.read
end
=> "1行目\n2行目\n3行目\n"
1行ずつ読み込み
texts = []
File.open("sample_file", "r") do |file|
file.each_line do |line|
texts << line
end
end
> texts
=> ["1行目\n", "2行目\n", "3行目\n"]
行頭に戻る
ファイルを読み込むと、ファイル内の特定の位置を示す、「ファイルポインタ」というものが更新されていきます。
なので、1度ファイルを読み取ってから、再度読み込むときは、このファイルポインタを戦闘にリセットする必要があります。
そこで使われるのが rewind メソッドです。
results = []
File.open("./sample_file", "r") do |file|
results << file.read
results << file.read
end
# 2回目の file.read が空文字になっている。
results
=> ["1行目\n2行目\n3行目\n", ""]
results = []
File.open("./sample_file", "r") do |file|
results << file.read
# ファイルポインタを先頭に戻す
file.rewind
results << file.read
end
# 2回目の file.read が取得できている。
results
=> ["1行目\n2行目\n3行目\n", "1行目\n2行目\n3行目\n"]
まとめ
今回は File クラスの扱いについて書きました。
次は CSV, Zlib の扱いに触れたいと思います!
Discussion