📂
Rubyでのディレクトリ・ファイル操作
- 環境
- Windows10
- Ruby 3.1.1
もっと便利なPathnameクラス
引数でパスを渡したとき
- パスの最後に
\
(円マーク)はつけてもつけなくてもいい- パスをダブルクオーテーションで囲うときは、エスケープ扱いにならないよう最後に円マークはつけないこと
呼び出し時.bat
ruby test.rb "C:\Users\xxx"
以下はRuby 3.1.1では不要(変換しなくてもそのままで動作する)
-
区切り文字は/
(スラッシュ)に置換する\
(円マーク)だとエスケープ文字扱いで検索などがうまく行かない
文字コードをutf-8にする
dir_path = ARGV[0]
puts dir_path # => C:\Users\xxx
dir_path = ARGV[0].gsub("\\", "/").encode(Encoding::UTF_8)
puts dir_path # => C:/Users/xxx
カレントディレクトリの取得
pwd = Dir.pwd
指定パスが存在するかチェック
真偽を返す
メソッド | trueを返す条件 |
---|---|
FileTest.exist?(path) |
pathが存在する |
FileTest.directory?(path) |
pathがディレクトリ |
FileTest.file?(path) |
pathがファイル |
if !FileTest.exist?(path)
raise ArgumentError, "パス #{path} は存在しません"
end
パスがワイルドカード指定の場合
file_path = "C:/Users/xxx/test*.txt"
if Dir.glob(file_path).empty?
raise ArgumentError, "パス #{file_path} が正しくありません"
end
ディレクトリ配下のファイルをすべて検索
※パスが存在しない場合はループに入らない(エラーも出ない)
# test以下のすべてのファイルを検索
Dir.glob("#{test}/**/*") do |path|
next if FileTest.directory?(path) # ディレクトリは無視
puts path
end
Dir.glob
の引数はワイルドカードで指定できる
ディレクトリ配下の拡張子付きファイル数を数える
file_num = Dir.glob("#{test}/**/*.*").count
ファイル名・ディレクトリ名を取得
一番最後のスラッシュに続く文字列を切り出している
path = "C:/Users/xxx/test.txt"
file_name = File.basename(path)
# => test.txt
path = "C:/Users/xxx"
dir_name = File.basename(path)
# => xxx
拡張子を取得
拡張子がない場合は空の文字列
path = "C:/Users/xxx/test.txt"
ext_name = File.extname(path)
# => .txt
テキストファイルの行数を取得
line_no = File.open("test.txt") do |file|
while file.gets;end # 最終行まで読み捨てる
file.lineno # 最終行の行番号を出力
end
puts line_no
ファイルを1行ずつ読み込む
# test.txt は UTF-8 で書かれている
File.foreach("test.txt", :external_encoding => "UTF-8") do |line|
line.chomp! # 改行削除
next if (line == "") # 空行を無視
puts line
end
行番号もほしいとき
File.foreach("test.txt", :external_encoding => "UTF-8").with_index(1) do |line, line_num|
puts "#{line_num}行目:#{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
csv形式のファイルを読み込む
一行ずつ配列として読み込む
require "csv"
CSV.foreach("test.csv", encoding: "UTF-8:UTF-8") do |csv_line|
csv_line.each do |cell|
puts cell
end
end
行番号・列番号付き
require "csv"
CSV.foreach("test.csv", encoding: "UTF-8:UTF-8").with_index(1) do |csv_line, line_num|
csv_line.each_with_index do |cell, column_num|
puts "#{line_num}行#{column_num + 1}列目:#{cell}"
end
end
csv形式のファイルとして出力
require "csv"
csv_arr = [[1, 2, 3], [4, 5, 6]]
CSV.open("test.csv", "w" ,:encoding => "UTF-8") do |csv|
# 1行ずつ出力
csv_arr.each do |row|
csv << row
end
end
下記が出力される
1,2,3
4,5,6
ファイルをコピーする
同名ファイルがある場合は上書きする
require 'fileutils'
src_path = "C:/..." # コピー元のパスを指定
dest_path = Dir.pwd
# src_path にあるファイルをカレントディレクトリへコピーする
FileUtils.copy(src_path, dest_path)
テキストファイルの文字コードを取得する
一回全部読み込んでからNKFで判定する
require 'nkf'
txt_path_str = "test.txt"
file = File.read(txt_path_str)
file_encode = NKF.guess(file).to_s # => UTF-8など
File.open(txt_path_str, :external_encoding => file_encode) do |file|
# 文字コードに合わせて開く
end
テキストファイルの改行コードがCR+LFか判定する
# 改行コードが変換されないようバイナリで開く
File.open("test.txt", "rb") do |file|
# 改行コードがCR+LFか判定
if file.read.include?("\r\n")
# -> CR+LFの改行コードがある
end
end
Discussion