背景
perlでログ出力する際に、csv形式、UTF-8で出力を行っていた。
そのため、cp932にエンコードしないとMS Officeで扱えない。。
目的
ログファイルをひとまとめにし、且つcp932で出力しMS Officeで扱えるようにする。
、、、本当は、色々とネタを増やしたかった。
作り始めてからの心情
ファイルまとめるくらい、すぐ作れるわ。ついでにtsvでも出力したろ。
↓
できた!、、、あれ、Windowsで動かないやん。。
↓
できた!、、、UTF-8のままじゃExcelでそのまま開けないやん。。
↓
できた!、、、ここまできたら、勉強で色々入れ込もう。
↓
やべぇ出来た。
↓
Qiitaに載せとこ!、、、え、ワンライナーでできるって?!うそだーーーーーーーーーーーー!!
__hageさんのコメントより
ruby -r nkf -e 'puts NKF.nkf("-s", ARGF.to_a.join)' (ログファイルがあるフォルダ)/* > (出力先ファイル名)
マジだ。。。
特長
WindowsでもMacでもLinuxでも同じ結果を返すはず。
というかWindowsが特殊説。
ソース
実行の方法
ruby combine_logfile.rb [-t] "ログファイルがあるフォルダ" "結合したログファイルの出力先ファイル名"
require 'fileutils'
require 'optparse'
require 'securerandom'
# あえてのオープンクラス
class String
# 引数用
def to_multi_pf_arg
windows? ? self.gsub(File::ALT_SEPARATOR) {File::SEPARATOR} : self
end
# 文字列用
def to_multi_pf_str
windows? ? self.encode('cp932') : self
end
private
# OS が windows か判定
def windows?
RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/
end
end
class FileManager
# コンストラクタ
def initialize(dir)
@dir ||= complete_slash(dir)
end
# ログファイルの結合
def combine_logfile(save_filename)
# すでに保存先にファイルがあったら、削除
FileUtils.rm save_filename if File.exist? save_filename
# 追記モードで保存先ファイルを開く
File.open(save_filename, 'a') do |write_f|
# 配列から順々にファイルを読み込み追記
list_logfile.each do |read_f|
p "Reading File: #{read_f.to_s}"
write_f << File.read(read_f, encoding: 'UTF-8')
end
end
# MS Officeで扱える文字コードに変換
encode_to_cp932 save_filename
p "Save to #{save_filename}"
end
# csv => tsv 変換
def to_tsv(save_filename)
tmp_filename = to_tmpfile(save_filename)
# comma を tab に置換
File.write save_filename, File.read(tmp_filename).gsub(',', "\t")
# 作業ファイルを削除
FileUtils.rm tmp_filename
end
private
# パスの末尾スラッシュ補完
def complete_slash(dir)
complete_slash_path = dir
if dir !~ /\/$/
complete_slash_path = dir + '/'
end
complete_slash_path
end
# .log ファイルを再帰的に検索
def list_logfile
# Dir.globメソッドで再帰的にチェックするためのおまじない
base_dir = @dir + '**/*.log'
Dir.glob(base_dir)
end
# MS Officeで扱える文字コードに変換
def encode_to_cp932(save_filename)
tmp_filename = to_tmpfile(save_filename)
# utf-8 => cp932 に変換
File.write(save_filename, File.read(tmp_filename, encoding: 'UTF-8'),
encoding: 'cp932:UTF-8')
# 作業ファイルを削除
FileUtils.rm tmp_filename
end
def to_tmpfile(filename)
# 作業ファイル用の乱数を生成
rand = SecureRandom.hex(6)
tmp_filename = filename + '.' + rand
FileUtils.mv filename, tmp_filename
tmp_filename
end
end
# コマンドラインでオプションを利用しやすくするためのインスタンスを生成
opt = OptionParser.new
# オプションを格納するためのハッシュ
OPTS = {}
# -t オプション設定
opt.on('-t') {|v| OPTS[:tsv] = v }
# オプションを配列から外す
opt.parse!(ARGV)
# 引数が2つなければエラー
if ARGV.size < 2
raise '引数が足りません。ログファイル格納場所, 結合したログファイル格納先 を指定して下さい'.to_multi_pf_str
end
# 第1引数: ログファイルのパス指定
target_dir = ARGV[0].to_s.to_multi_pf_arg
# 第2引数: 結合したログファイルのパス指定
save_filename = ARGV[1].to_s.to_multi_pf_arg
# FileManagerのインスタンス生成
file_mgr = FileManager.new(target_dir)
# ログファイルの結合
file_mgr.combine_logfile save_filename
# '-t' オプションがあれば、tsvで出力
if OPTS[:tsv]
file_mgr.to_tsv save_filename
end
実際書いてみて
WindowsとMacの差を埋めるのつらたん。
もっと汎用的に使える物作りたい。。