Rubyでのディレクトリ・ファイル操作

公開:2021/02/19
更新:2021/02/26
2 min読了の目安(約2600字TECH技術記事
  • 環境
    • Windows10
    • Ruby 2.7.2

もっと便利なPathnameクラス

https://zenn.dev/kunosu/articles/379ee3eedc413c07de6f

引数でパスを渡したとき

  • パスの最後に\(円マーク)はつけてもつけなくてもいい
    • パスをダブルクオーテーションで囲うときは、エスケープ扱いにならないよう最後に円マークはつけないこと
呼び出し時.bat
ruby test.rb "C:\Users\xxx"
  • 区切り文字は /(スラッシュ)に置換する
    • \(円マーク)だとエスケープ文字扱いで検索などがうまく行かない
  • 文字コードをutf-8にする
dir_pass = ARGV[0]
puts dir_pass # => C:\Users\xxx

dir_pass = ARGV[0].gsub("\\", "/").encode(Encoding::UTF_8)
puts dir_pass # => C:/Users/xxx

カレントディレクトリの取得

初めから /(スラッシュ)なので文字コードの変換だけでいい

pwd = Dir.pwd.encode(Encoding::UTF_8)

指定パスが存在するかチェック

真偽を返す

メソッド trueを返す条件
FileTest.exist?(pass) passが存在する
FileTest.directory?(pass) passがディレクトリ
FileTest.file?(pass) passがファイル
if !FileTest.exist?(pass)
	raise ArgumentError, "パス #{pass} は存在しません"
end

パスがワイルドカード指定の場合

file_pass = "C:/Users/xxx/test*.txt"
if Dir.glob(file_pass).empty?
	raise ArgumentError, "パス #{file_pass} が正しくありません"
end

ディレクトリ配下のファイルをすべて検索

※パスが存在しない場合はループに入らない(エラーも出ない)

# test以下のすべてのファイルを検索
Dir.glob("#{test}/**/*") do |pass|
	next if FileTest.directory?(pass)	# ディレクトリは無視
	puts pass
end

Dir.glob の引数はワイルドカードで指定できる

ディレクトリ配下の拡張子付きファイル数を数える

file_num = Dir.glob("#{test}/**/*.*").count

ファイル名・ディレクトリ名を取得

一番最後のスラッシュに続く文字列を切り出している

pass = "C:/Users/xxx/test.txt"
file_name = File.basename(pass)
# => test.txt
pass = "C:/Users/xxx"
file_name = File.basename(pass)
# => xxx

ファイルを1行ずつ読み込む

# test.txt は UTF-8 で書かれている
File.foreach("test.txt", :external_encoding => "UTF-8") do |line|
	line.chomp!	# 改行削除
	next if (line == "")	# 空行を無視

	puts line
end

xml形式のファイルを読み込む

下記のファイルから123,456,789を読み込む

<list>
	<id>123</id>
	<id>456</id>
	<id>789</id>
</list>
require 'rexml/document'

File.open("test.xml", :external_encoding => "UTF-8") do |file|
	xml = REXML::Document.new(file)
	xml.elements.each("list/id") do |element|
		puts element.text
	end
end

下記のファイルから123,456,789を読み込む

<list>
	<a id=123>
	<a id=456>
	<a id=789>
</list>
require 'rexml/document'

File.open("test.xml", :external_encoding => "UTF-8") do |file|
	xml = REXML::Document.new(file)
	xml.elements.each("list/a") do |element|
		# Hash形式で取得{"id" => 123}
		hash = element.attributes
		puts hash["id"]
	end
end

ファイルをコピーする

同名ファイルがある場合は上書きする

require 'fileutils'

src_pass = "C:/..." # コピー元のパスを指定
dest_pass = Dir.pwd.encode(Encoding::UTF_8)    # 文字コードを統一する

# src_pass にあるファイルをカレントディレクトリへコピーする
FileUtils.copy(src_pass, dest_pass)