WIN32APIをそのまま触るとつらかったのでラッパーにしてみました。Windows専用です。
Excelファイルのシート単位で2次元配列として読みだして、慣れてるオブジェクト操作をして、出来上がったものをシート単位で書きだそう、という考えを適用しています。2次元配列ならみんな慣れてるので楽です。
WIN32OLEを直接触ることで他の操作も可能です。
なお、ExcelのWIN32APIのラッパーはWrapExcelというGemがあります。
使い方
インスタンス生成時にファイルを指定します。相対パスでも絶対パスでも可能です。
存在しないファイルを指定した場合には、新規作成となります。
末行に値を追加する
xl = ExcelTable.new('Book1.xlsx')
# Sheet1を2次元配列として読み出す
# シートの指定は数字でも可能
table = xl.read("Sheet1")
table # => [["tes"]]
# 2次元配列を編集する
row = ["hoge", "ふが", Time.now, true, false, nil, 33, 3.14 ] # これらが使用可能なオブジェクト
table << row # 1行追記する
# 2次元配列をSheet1に反映
xl.write(table, "Sheet1")
# 変更を保存して終了
xl.close
close
を忘れたり例外によって停止した場合、at_exit
によってExcelを「変更を保存せずに終了」します。
コード
excel_arrays.rb
class ExcelTable
def initialize(file_path)
require 'win32ole'
@excel = WIN32OLE.new('Excel.Application')
@fp = WIN32OLE.new('Scripting.FileSystemObject').GetAbsolutePathName(file_path)
# cf. http://d.hatena.ne.jp/maluboh/20070709/p1
@wbook = if File.exist?(@fp)
@excel.Workbooks.Open(@fp)
else
@excel.Workbooks.Add
end
@allow_type = [ String, Numeric, Time, TrueClass, FalseClass, NilClass ]
raise "\n#{file_path} は既に開かれているか読み取り専用です" if @wbook.Readonly
# 例外時でもちゃんと閉じる
# (不十分な実装)@excelが既に閉じているかどうかを調べるWIN32API関数?
at_exit{ begin close(false) rescue nil end }
end
attr_accessor :excel, :wbook, :allow_type, :fp
def read(sheet_key=1)
sheet2table(@wbook.sheets[sheet_key])
end
def write(table, sheet_key=1)
value_type_checking = table.all?{|a| a.all?{|v| @allow_type.any?{|type|v.kind_of?(type)} } }
raise "非対応の型が含まれています" unless value_type_checking
table2sheet(table, @wbook.sheets[sheet_key])
end
def close(is_save=true)
if is_save
@excel.DisplayAlerts = false
@wbook.SaveAs(@fp)
end
@wbook.Close
@excel.Quit
end
private
def sheet2table(sheet)
sheet.UsedRange.Rows.each.map{|row|
a = row.Value
a[0].class == Array ? a[0] : [a]
}
rescue
[]
end
def table2sheet(table, sheet)
table.each.with_index(1) do |arr, i|
arr.each.with_index(1) do |val, j|
sheet.Rows[i].Columns[j] = val
end
end
end
end
おことわり
数式に対応していません。「=A1+A2」で計算結果が3.0のセルがあるとき、このラッパーはそれを3.0
として読み込みます。さらに、ExcelTable#write
はシート上の数値を全て上から値貼り付けするので、もとの「=A1+A2」という情報は失われます。
存在しないシートを指定したなど、例外処理してない例外はmethod_missing
になります。