組み込みクラス: IO編

Fileクラスのスーパークラスなので、IOクラスのメソッドの多くはFileクラスでも使用可能。

IOを開く

Fileの時と同じく、openは第二引数でモードを指定しなければ、readモードとなる。

io = open("text.txt","r+"){ |io|
  io.write("HelloWorld from Ruby IO.")
  puts io.write
}

IOクラスではコマンドの出力結果を得ることができる。openメソッドの引数の一番前にパイプを差し込むことで実現できる。

irb(main):002:0> io = open("|ls -a")
(irb):2: warning: Insecure world writable dir /home/pyons/.rbenv/versions in PATH, mode 040777
=> #<IO:fd 9>
irb(main):003:0> io.read
=> ".\n..\n.bash_history\n.bash_logout\n.bash_profile\n.bashrc\n.bundle\n"

定数STDOUTを用いれば、標準出力に対して書き込みを行うこともできる。

irb(main):001:0> p STDOUT.write("heloworld")
heloworld9
=> 9

IOオブジェクトにはreadモードとwriteモードでそれぞれ異なる、IO閉じメソッドが用意されているようだが、今のところ使い方が良く分かっていない。

io = open("text.txt","r+"){ |io|
  io.write("HelloWorld from Ruby IO.")
  io.close_write
  puts io.write
}
PS C:\Users\broad\Desktop> ruby .\dir.rb                                            
Traceback (most recent call last):
        3: from ./dir.rb:33:in `<main>'
        2: from ./dir.rb:33:in `open'
        1: from ./dir.rb:35:in `block in <main>'
./dir.rb:35:in `close_write': closing non-duplex IO for writing (IOError)

IOからの入力

IO.read

openされたIOから内容をすべて読み込む。また、引数で読み込む長さを指定することもできる。 IOクラスのインスタンスであるioオブジェクトからも実行することが出来る。

p IO.read("text.txt",7)
"HelloWo"

openメソッドがいきなり出てくる点に戸惑うが、openメソッドはクラスを指定せずにインスタンスが生成される模様。

module function Kernel.#open (Ruby 2.6.0)

io = open("text.txt","r+")
p io.read
PS C:\Users\broad\Desktop> ruby .\dir.rb 
"HelloWorld from Ruby IO."

IO.foreach

IOクラスから一行ずつ読み込み、ブロックに送り込む。 IOクラスのインスタンスからも実行可能だが、その場合eachまたはeach_linesとメソッド名が変わる。

io = open("text.txt","r+")
p io.each{ |line|
 p line
}

IO.foreach("text.txt"){ |line|
 p line
}
PS C:\Users\broad\Desktop> ruby .\dir.rb                                            
"HelloWorld from Ruby IO.\n"
"This is test file to check the IO class.\n"
"I hope tomorow test will be fine.\n"
" "
#<File:text.txt>
"HelloWorld from Ruby IO.\n"
"This is test file to check the IO class.\n"
"I hope tomorow test will be fine.\n"
" "

一方readlinesはファイルをすべて読み込んで、配列で返す。

irb(main):001:0> io = open("text.txt")
=> #<File:text.txt>
irb(main):002:0> io.readlines
=> ["HelloWorld from Ruby IO.\n", "This is test file to check the IO class.\n", "I hope tomorow test will be fine.\n", " "]

一行ずつ読み込ませるにはgets(標準入力も一行の読み込み)やreadlineを使う。

irb(main):004:0> io = open("text.txt")
=> #<File:text.txt>
irb(main):005:0> io.readline
=> "HelloWorld from Ruby IO.\n"
irb(main):006:0> io.gets
=> "This is test file to check the IO class.\n"
irb(main):007:0> io.readline
=> "I hope tomorow test will be fine.\n"
irb(main):008:0> io.gets
=> " "
irb(main):009:0> io.readline
Traceback (most recent call last):
        5: from C:/Ruby26-x64/bin/irb.cmd:31:in `<main>'
        4: from C:/Ruby26-x64/bin/irb.cmd:31:in `load'
        3: from C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        2: from (irb):9
        1: from (irb):9:in `readline'
EOFError (end of file reached)

バイトごとに一文字ずつ読み込んで、整数で返すこともできる。

irb(main):006:0> io = open("text.txt","r+")
=> #<File:text.txt>
irb(main):007:0> byte = io.getbyte
=> 72
irb(main):008:0> byte.chr
=> "H"
irb(main):009:0> byte = io.getbyte
=> 101
irb(main):010:0> byte.chr
=> "e"

read_byteというエイリアスも存在する。

一文字ずつの読み込みはgetcまたはread=char

irb(main):011:0> io = open("text.txt","r+")
=> #<File:text.txt>
irb(main):012:0> io.getc
=> "H"
irb(main):013:0> io.getc
=> "e"
irb(main):014:0> io.getc
=> "l"
irb(main):015:0> io.getc
=> "l"
irb(main):016:0> io.getc
=> "o"
irb(main):017:0> io.getc
=> "W"

each_charという一文字ずつ読み込んでブロックに渡すメソッドも存在する。

io = open("text.txt","r+")
array = []
io.each_char{|chr| array << chr}
p array
PS C:\Users\broad\Desktop> ruby .\dir.rb
["H", "e", "l", "l", "o", "W", "o", "r", "l", "d", " ", "f", "r", "o", "m", " ", "R", "u", "b", "y", " ", "I", "O", ".", "\n", "T", "h", "i", "s", " ", "i", "s", " ", "t", "e", "s", "t", " ", "f", "i", "l", "e", " ", "t", "o", " ", "c", "h", "e", "c", "k", " ", "t", "h", "e", " ", "I", "O", " ", "c", "l", "a", "s", "s", ".", "\n", "I", " ", "h", "o", "p", "e", " ", "t", "o", "m", "o", "r", "o", "w", " ", "t", "e", "s", "t", " ", "w", "i", "l", "l", " ", "b", "e", " ", "f", "i", "n", "e", ".", "\n", " "]

EOF(End of File)になったときに挙動はそれぞれメソッドによって異なるが、ここでは省略する。

ここまで入力用の様々なメソッドを見てきたが、今度は出力用メソッドを見てみる。

通常の出力はwriteであるが、putsprintメソッドは複数の引数をとれる。

io = open("text.txt","r+")
array = []
io.puts("Write","Test","From","Ruby")
io.each_line{|chr| array << chr}

p array
PS C:\Users\broad\Desktop> ruby .\dir.rb
["\n", "This is test file to check the IO class.\n", "I hope tomorow test will be fine.\n", "Write\n", "Test\n", "From\n", "Ruby\n"]
  • putsprintは正確には挙動が若干異なるようだが、あまり理解できていない。

printfは指定されたフォーマットで文字列を出力する。

irb(main):003:0> STDOUT.printf("%05d","9999")
09999=> nil
irb(main):005:0> STDOUT.printf("%08d","9999")
00009999=> nil

また、「putc」というメソッドは「一文字だけの出力」を行うが、 * 整数の引数の場合は最下位のバイトを文字コードとする文字 * 文字列の場合は先頭の一文字 * どちらでもなければ(例:8進数など)to_iメソッドで整数化して文字コードを出す

ことで出力している。

irb(main):002:0> STDOUT.putc("a")
a=> "a"
irb(main):005:0> STDOUT.putc(65)
A=> 65
irb(main):006:0> STDOUT.putc("HelloWorld")
H=> "HelloWorld"
irb(main):007:0> STDOUT.putc(0o101)
A=> 65