📄

【Ruby】ファイル操作をするクラスとメソッド

2022/05/09に公開

Fileクラス

ファイルに関するクラスです。
ファイルの作成、削除、閉じる、読み込みや書き込み、属性の変更など様々なメソッドがあります。

https://docs.ruby-lang.org/ja/latest/class/File.html

ファイルのモード

Fileクラスのメソッドの第2引数には、ファイルのモードを指定できます。
ファイルに書き込したり、追記する場合に指定します。何も指定しなければ、読み取りモードになります。

オプション 説明
読み込み
w 書き込み。既存ファイルの場合は、ファイルの中身を空にする
a 追記。ファイルの末尾に追記される
r+ 読み書き。ファイルの先頭から読み書きを行う。
w+ 読み書き。既存ファイルの場合は、ファイルの中身を空にする
a+ 読み書き。ファイルの末尾から読み書きを行う。

ファイルを開く

メソッドは、「open」です。
ファイルモードは全てのオプションを指定できます。

構文

File.open("ファイル名", "ファイルモード")

(例) sample.txtを開きます。

File.open('sample.txt')

ファイルを読み込む

メソッドは、「read」です。

構文

インスタンス変数名.read(length)

readの引数lengthには、読み込むサイズを整数で指定します。

sample.txt

(例) sample.txtの内容を読み込みます

file = File.open('sample.txt')
puts file.read
出力結果
Hello World
Hello Ruby
Hello Java

(例) Hello Worldだけ読み込む場合は、readの引数に11を指定する

file = File.open('sample.txt')
puts file.read(11)
Hello World

ファイルを閉じる

メソッドは、「close」です。
基本的にファイルは開く・閉じるはセットです。

構文

インスタンス変数名.close

(例) sample.txtを開いて、閉じます。

file = File.open('sample.txt')
=> #<File:sample.txt>
file.close
=> nil

閉じ忘れ防止のために、ブロック形式にすると終了時に自動的にファイルが閉じます。
基本はブロック形式で記述しましょう。

File.open('sample.txt') { |file| puts file.read }

ファイルの作成

メソッドは、「new」と「open」です。(一般的には「open」を使うことが多いです。)
メソッドの第一引数には「ファイル名」を第2引数には、ファイルモードを指定します。
ファイルモードは、「w」か「w+」、「a」か「a+」を指定します。

構文

File.open("ファイル名", "ファイルモード")

(例) sample.txtを書き込みモードで作成します。

file = File.open('sample.txt', "w")

実行すると、sample.txtが作成されました。

ファイルに書き込む

メソッドは、「write」です。(putsでも可能)
ファイルモードは、「r+」、「w」か「w+」、「a」か「a+」を指定します。

構文

インスタンス変数名.write("書き込むもの")

(例) sample.txtの中に書き込みます

file = File.open('sample.txt', "w")
file.write("Hello Ruby")

ブロックで処理することもできます。

File.open('sample.txt', "w") do |io|
  io.write("Hello Ruby")
end

(例) sample.txtというファイルに「Hello Ruby」が書き込まれる

ファイルを削除する

メソッドは、「delete」です。

構文

File.delete("ファイル名")

(例) sample.txtを削除します。

File.delete('sample.txt')
=> 1

IOクラス

Fileクラスのスーパークラスで、基本的な入出力機能を備えたクラスです。
read,write,closeなど多くのメソッドは前述で紹介したFileクラスでも使用できます。

https://docs.ruby-lang.org/ja/latest/class/IO.html

sample.txtの内容を例にそれぞれのメソッドについて説明します。

sample.txt
Hello World
Hello Ruby
Hello Java

ファイルの読み込み

foreach / each_line / each

引数で指定したファイルを開いて、各行をブロックに渡して実行します。

# foreach
IO.foreach("sample.txt") {|i| puts i}

# each_line
io = open("sample.txt")
io.each_line("sample.txt") {|i| puts i}

# each
io = open("sample.txt")
io.each("sample.txt") {|i| puts i}
出力結果
Hello World
Hello Ruby
Hello Java

readlines

ファイルを全て読み込んで、各行を配列として返します。

File.open("sample.txt").readlines
=> ["Hello World\n", "Hello Ruby\n", "Hello Java"]

gets / readline

ファイルから一行読み込んで、読み込みに成功した時にはその文字列を返します。

getsとreadlineの違いは、EOFに到達した時です。getsはnil,readlineはEOFErrorを返します。

io = open("sample.txt")
=> #<File:sample.txt>

io.gets
=> "Hello World\n"

> io.gets
=> "Hello Ruby\n"

> io.gets
=> "Hello Java"

io.gets
=> nil

eof?

ファイルの終端まで達したかどうかを調べるメソッドです

先程のファイルでio.getsでnilになったので、終端になっています。
eof?メソッドで終端に達したかどうかを確認できます。

io = open("sample.txt")
io.gets
=> #<File:sample.txt>
=> "Hello World\n"
> io.gets
=> "Hello Ruby\n"
> io.gets
=> "Hello Java"
io.gets
=> nil

io.eof?
=> true

ファイルのポインタの移動や設定

開いたファイルの読み書きをする場所、ファイルのポインタの移動や設定をするメソッドがあります。

rewind

ファイルポインタを先頭に移動して、行番号(lineno)を0にします。

io = open("sample.txt")
=> #<File:sample.txt>
io.readline   
=> "Hello World\n"

# 0になります
io.rewind    
=> 0

# 行番号(lineno)が0になります
io.lineno   
=> 0

io.readline
=> "Hello World\n"

pos

ファイルポインタの位置を取得したり、指定できます。

io = open("sample.txt")
=> #<File:sample.txt>
io.readline     
=> "Hello World\n"

# "Hello World\n"は、12番目です。
io.pos 
=> 12

# ファイルポインタを18に指定します。
io.pos = 18

# 18番目から読み込みます。
io.read
=> 18
=> "Ruby\nHello Java"

seek

ファイルポインタを指定した数だけ第2引数の位置から移動します。
位置への移動が成功すれば0を返します。

<第2引数>
IO::SEEK_SET:ファイルの先頭から (デフォルト)
IO::SEEK_CUR:現在のファイルポインタから
IO::SEEK_END:ファイルの末尾から

io = open("sample.txt")
=> #<File:sample.txt>

# ファイルポインタを5番目に移動
io.seek(5)
=> 0
# 6番目から読み込み
io.read
=> " World\nHello Ruby\nHello Java"

# ファイルの先頭からポインタを10番目に移動
io.seek(10, IO::SEEK_SET)
=> 0
# 11番目から読み込み
io.read
=> "d\nHello Ruby\nHello Java"

例題

Ruby技術者認定試験合格教本にある模試問題です。

①無限ループ処理

File.open("sample.txt") do |io|
  # while not(=until)→指定した条件が満たされるまで ループを実行します。
  # ファイルが終端に達する(trueになる)までループする
  while not io.eof?
    # readの引数は、読み込むサイズを整数で指定するので、1は「H」になる
    print io.read(1)
    # ファイルの先頭から読み込む
    io.seek(0, IO::SEEK_SET)
  end
end

「H」が無限ループする

出力結果
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
HHHHHHHHHHHHHHHHHH.............

②ファイルの文字を逆順に書き込む処理

sample.txt
123456789
open("sample.txt", "r+") do |f|
  data = f.read
  data.reverse!
  f.rewind
  f.write(data)
end

逆順に書き込まれる

sample.txt
987654321

コードの解説

open("sample.txt", "r+") do |f|
    # ファイルを読み込む
  data = f.read
  => "123456789"
  
  # 逆順にします
  data.reverse!
  => "987654321"
  
  # ファイルポインタを0にします
  f.rewind
  => 0
  
  # 出力できたバイト数(今回は9文字)を返します。
  f.write(data)
  => 9
end

Discussion