#author("2018-05-26T21:24:03+09:00","default:wikiwriter","wikiwriter") #author("2021-06-24T04:40:59+00:00","default:src128","src128") [[Ruby]] &tag(Ruby/ファイル); *目次 [#lb1cce5d] #contents *関連ページ [#tb90eef1] *参考情報 [#f105bf57] -[[Ruby]] -[[ワイルドカードにマッチするパスの一覧を取得する - Ruby Tips!:http://rubytips86.hatenablog.com/entry/2014/03/28/145056]] *ファイル読み込み [#xeccee68] **オーソドックスな方法で読み込む [#bd0afe89] -openした後にreadする #pre{{ #オーソドックスな読み込み File.open("/tmp/test.txt") do |f| puts f.read end }} **一行で読み込む[#s8c722e9] -File.readを使う #pre{{ str = File.read("/tmp/test.txt") puts str }} **一行ずつの配列として読み込む [#pb01f87d] -File.readlinesを使う。行末の改行コードは残っている File.readlines(path) *ファイル書き出し[#i1984b49] **オーソドックスな方法で書き出す [#g55042a4] -openした後writeする。 #pre{{ File.open("/tmp/test.txt", "w") do |f| f.puts("This is test1") end }} **一行で書き出す [#rcc2ce1b] -File.writeが使える File.write("/tmp/text.txt", "This is test") **BOM付きUTF-8ファイルを書き出す [#i9f1f0fa] -手作業でやるしかない? #pre{{ def write_bom(fp) data = " " data.setbyte(0, 0xEF) data.setbyte(1, 0xBB) data.setbyte(2, 0xBF) fp.write(data) end }} *ファイル読み書き時のエンコーディング指定 [#zb4c8f38] -[[module function Kernel.#open (Ruby 2.5.0):https://docs.ruby-lang.org/ja/latest/method/Kernel/m/open.html]]に以下のような説明がある。文字列("mode" か "mode:ext_enc" か "mode:ext_enc:int_enc" という形式)か 整数(File::Constants モジュールの定数の論理和)を組み合わせて指定します。 -すなわち以下のように指定。 #pre{{ # 読み込み時、書き込み時関係なく"モード:外部エンコーディング:内部エンコーディング"の順に指定。 File.open("/tmp/cp932.txt", "w:CP932:UTF-8") do |f| f.puts("これはテストです") end File.open("/tmp/cp932.txt", "r:CP932:UTF-8").each_line do |line| puts line end }} *ファイル検索 [#ra838a88] **Dir::globを使う [#l759e827] *** ディレクトリに含まれるjpgファイル全てをフルパスの配列として取得する[#u976fc5f] -一つの拡張子 Dir.glob("/tmp/*.jpg") => ["d:/temp/empty.jpg", "d:/temp/ipad.jpg"] ***ディレクトリに含まれるhtm/htmlファイル全てをフルパスの配列として取得する [#u769aaba] -複数の拡張子 Dir.glob("*.{htm,html}") ***サブディレクトリ以下を含むディレクトリに含まれるjpgファイル全てをフルパスの配列として取得する [#o55a96c3] -"**"を使う Dir.glob("/tmp/**/*.jpg") *** globの引数 [#o29f25e8] ワイルドカードを指定できる(正規表現ではない)。 :*|空文字列を含む任意の文字列と一致。 :?|任意の一文字と一致。 :[ ]|括弧内のいずれかの文字と一致。 :{ }|コンマで区切られた文字列の組合せに展開。 :**/|ディレクトリを再帰的にたどってマッチを行う。 **Dir::entriesを使う [#x97c13e8] *** /tmpに含まれるファイル全てを配列として取得する。 [#q384f8b9] p Dir::entries("d:/temp") => [".", "..", "empty.jpg", "ipad.jpg"] 戻り値はファイル名のみ。 *** /tmpに含まれるファイル全てをフルパスの配列として取得する。 [#n3c9237c] dir = "d:/temp/" p Dir.entries(dir).collect{|f| dir + f} => ["d:/temp/.", "d:/temp/..", "d:/temp/empty.jpg", "d:/temp/ipad.jpg"] *** /tmpに含まれるjpgファイル全てをフルパスの配列として取得する [#yf50238d] dir = "d:/temp/" p Dir.entries(dir).grep(/\.jpg$/) {|f| dir + f} => ["d:/temp/empty.jpg", "d:/temp/ipad.jpg"] *** /tmpに含まれるjpg,pngファイル全てをフルパスの配列として取得する [#x54e91b9] grepに渡す正規表現を工夫すればよい。 dir = "d:/temp/" p Dir.entries(dir).grep(/\.(jpg|png)$/) {|f| dir + f} => ["d:/temp/abc.png", "d:/temp/empty.jpg", "d:/temp/ipad.jpg"] *ファイルを削除する [#v4efa279] **FileUtils.rmを使う [#cb4da459] ***ファイルを一つだけ削除 [#ha3bffa3] FileUtils.rm("d:/temp/foo.txt") *** ワイルドカードにマッチするファイルを削除 [#ce50d17a] FileUtils.rm(Dir.glob("d:/temp/*.jpg")) *ファイルのテスト [#cf398297] **バイナリファイルかどうかをテスト [#v3bfaf61] -[[djberg96/ptools: Extra methods (power tools) for the File class for Ruby:https://github.com/djberg96/ptools]]を使う。 -あるいは[[How to check if a file is a human readable text file - makandra dev:https://makandracards.com/makandra/483046-how-to-check-if-a-file-is-a-human-readable-text-file]]で説明されているメソッドが使えるのか? #pre{{ # Returns whether or not +file+ is a binary file. Note that this is # not guaranteed to be 100% accurate. It performs a "best guess" based # on a simple test of the first +File.blksize+ characters. # # Example: # # File.binary?('somefile.exe') # => true # File.binary?('somefile.txt') # => false #-- # Based on code originally provided by Ryan Davis (which, in turn, is # based on Perl's -B switch). # def self.binary?(file) s = (File.read(file, File.stat(file).blksize) || "").split(//) ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30 end }} *パスの操作 [#j3f25b5a] **File.expand_pathの第2引数について [#b1dfed6c] -[[RubyのFile.expand_path('相対パス', __FILE__)の意味 - maeharinの日記:http://d.hatena.ne.jp/maeharin/20130104/p1]]。 -File.expand_path('./lib', __FILE__)とすると、"〜a.rb/lib"のように展開される。これはexpand_pathが第二引数がファイル名であろうとそのまま基準ディレクトリとして扱うため。 -ファイル名部分を打ち消すためは、File.expand_path('../lib', __FILE__)とする。 -応用として、testディレクトリにあるテストファイルから、親ディレクトリにある本番rubyスクリプトをrequireするとき次のようにすればよい。"../"の一つは上記のうちけしでつかわれるので二重になっている。 require File.expand_path('../../a.rb', __FILE__) **Pathname [#aff82616] -pathを操作するための専用クラス。 #pre{{ require 'pathname' path = Pathname.new("/tmp") path += 'sample.txt' #結合できる。戻り値はPathnameオブジェクト p path # => #<Pathname:/tmp/sample.txt> }} *Zipファイルの取り扱い [#w58868c9] ** Rubyzipを使用する [#g3416bf2] .zipファイルを圧縮解凍するためのライブラリ。 ***Rubyzipで解凍する [#i11a99aa] -指定したzipファイルをtmpフォルダ以下に解凍するサンプル #pre{{ Zip::File.open('data/demo.zip') do |zipfile| zipfile.each do |entry| puts "extracting #{entry.name}" entry.extract('tmp/' + entry.name) end end }} *トラブルシューティング [#ed06a0ca] **ファイルに出力すると^Mが表示される。 [#a3f30012] -[[^M (ハットM)記号について - Fakin'it:http://fakinit.xrea.jp/fakinit/2009/07/m-m.html]]に書いてあるように、^MはCR(=\r)に相当することを前提として、例えば次ぎのようなプログラムをWindows環境で動かす。 #pre{{ f = File.open("log.txt", "w") f.print("abc\r\n") f.close }} -するとlog.txtには次のような文字が書き出される(しかもエディタで見るとcrlfモード)。 abc^M -これはファイルをテキストモードで書き出しオープン(="w")しているため。\nが\r\nに変換されて書き出されるため、結局ファイルには"abc\r\r\n"が書き出されていることになる。末尾の\r\nがcrlfモードとしてエディタに認識され、残った\rが^Mとして画面に表示されることになる。