Ruby基礎復習(8) Fileクラス
『パーフェクトRuby』p.196より。わりと苦手な分野。
まずはファイルをひらく。#open
して変数に格納してもいいし、ブロックを引き渡して処理させることもできる。後者の場合は処理が終わると自動でクローズしてくれるので、こっちの方が楽っぽい。#read
はファイルの内容全体を読み込む一方、#gets
を使うと1行ずつ読み込むことができる。あるいは#each_line
や#each_char
といったメソッドも。
1file = File.open('example.txt')
2p file.read # example.txtの内容を表示
3file.close
4
5File.open 'example.txt' do |file|
6 p file.read
7end
8
9File.read('example.txt')
10
11File.open 'example.txt' do |file|
12 while line = file.gets
13 p line
14 end
15end
16
17File.open 'example.txt' do |file|
18 f.each_line do |line|
19 p line
20 end
21end
書き込むときは#open
の第二引数にファイルを開くモードを指定する。デフォルトは'r'
、すなわち読み込みモードで、他は以下の通り。基本はr
が読み込み、w
が書き込み、a
が追記で、+
を付けると読み書き両用モードになる。またb
を後置するとバイナリモードで開かれる。
| r | 読み込みモード | | r+ | 読み書き両用モード(読み書き位置は先頭から) | | w | 上書き書き込みモード | | w+ | 新規作成して読み書き両用モード | | a | 追記書き込みモード | | a+ | 追記読み書き両用モード(読み込み位置は先頭から、書き込みは追記形式) |
1File.open 'example.txt', 'w' do |f|
2 f.write 'hoge'
3end
もっと単純に#write
メソッドだけでも書き込み可能。
1File.write 'example.txt', 'fuga'
先のファイルを開くモードの話の中で「読み込み位置は先頭から」という表現があったが、IOオブジェクトではファイル内の今どこを読み/書きしているかというアクセス位置が存在する。#gets
では1行ずつ読み込みを行ったように、読み/書きを行うことでアクセス位置は進んでいく。先頭まで戻りたい場合は#rewind
を使う。また#seek
メソッドは第二引数に定数で指定した基準位置より、第一引数の整数分アクセス位置を移動させることができる。#pos
は絶対的にアクセス位置を指定して動かせる。
1File.open 'example.txt' do |f|
2 f.puts
3 f.rewind # 先頭位置まで戻る
4
5 f.seek 10 # 先頭から10進む
6 f.seek -10, IO::SEEK_END # 末尾(SEEK_END)から10戻った位置に移動
7
8 f.pos = 25 # 先頭から25バイト目に移動
9 f.pos # => 25
10end
文字のエンコーディングについては、「外部」と「内部」という概念を持つ。外部はファイルのエンコーディング情報であり、内部はRuby上で処理する際のエンコーディング情報。例えばEUC-JPのファイルをutf-8で変換して取り扱い、書き込みはEUC-JPで、といったことができる。エンコーディングの設定には#set_encoding
メソッドを使う。引数を1つだけ取る場合は外部エンコーディングを設定し、2つ取る場合は第一引数が外部、第二引数が内部を設定する。あるいはFile#open
するときに、読み書きモードと一緒にエンコーディングも指定することができる。
1File.open 'example.txt' do |f|
2 f.set_encoding('utf-8') # 外部エンコーディングをutf-8に設定
3
4 f.set_encoding('utf-8', 'EUC-JP') # 外部エンコーディングをutf-8、内部エンコーディングをEUC-JPに設定
5 f.set_encoding('utf-8:EUC-JP') # 外部エンコーディングをutf-8、内部エンコーディングをEUC-JPに設定
6end
7
8File.open 'example.txt', 'r:utf-8:EUC-JP' do |f|
9 p f.external_encoding # => "utf-8"
10 p f.internal_encoding # => "EUC-JP"
11end
ファイルのロックには#flock
メソッドを利用する。ロックのモードはここに記載の定数を使って指定するのだが、主にFile::LOCK_EX
が排他ロックであることを覚えとけばいいような気も。
1File.open 'example.txt', 'w' do |f|
2 f.flock File::LOCK_EX
3end
その他、ファイル情報取得系のメソッドをつらつらと。これらはファイルオブジェクトから取得するだけではなく、File.atime(filename)
の形でFile
クラスのクラスメソッドでも呼び出すことができる。
1File.open 'example.txt' do |f|
2 f.atime # 最終アクセス日時
3 f.ctime # 最終変更日時
4 f.mtime # 最終更新日時
5
6 f.size # ファイルサイズ
7
8 f.ftype # ファイルタイプ 以下真偽判定メソッドも有り
9 f.file?
10 f.directory?
11 f.symlink?
12
13 f.writable? # => false
14 f.readable? # => true
15 f.executable? # => false
16
17 f.owned? # => false (自身がファイル所有者か?)
18 f.gid # ファイル所有者のGID
19 f.uid # ファイル所有者のUID
20end
ファイル操作系。
1# ファイル名変更、ファイル移動
2File.rename 'hoge', 'fuga'
3File.rename 'hoge', 'dir/hoge'
4
5# ファイル削除
6File.unlink 'hoge'
7
8# シンボリックリンク作成
9File.symlink 'target', 'link'
10
11# ハードリンク作成
12File.link 'target', 'link'
13
14# ファイルモード変更
15File.chmod 0600, 'filename'
16
17# 所有者、グループの変更
18File.chown 100, 100, 'filename'
ファイルパスに関するもろもろ。
1# ファイルのあるディレクトリパスの取得
2File.dirname("etc/sample.txt") # => "/etc"
3
4# 第一引数に与えたファイルパスに対する、ファイル名の取得。第二引数でsuffix指定。
5File.basename("etc/sample.txt") # => "sample.txt"
6File.basename("etc/sample.txt", ".txt") # => "sample"
7
8# 拡張子の取得
9File.extname("etc/sample.txt") # => ".txt"
10
11# ファイルパスの連結(引数は可変長)
12File.join("/usr/local", "bin/ruby") # => "/usr/local/bin/ruby"
13
14# ファイルパスからdirnameとbasenameを取得し配列生成
15File.split("/usr/local/bin/ruby") # => ["/usr/local/bin", "ruby"]
16
17# 絶対パスの展開
18File.expand_path("~") # => "/home/chroju"
19File.expand_path("filename", "~") # => "/home/chroju/filename"
20
21# absolute_pathでは~を展開しない
22File.absolute_path("~") # => "/home/chroju/~"
Dirクラスも触れたいのだが、長くなるので一旦ここまで。