MDBにあるテーブルを全てCSV形式で出力する
MDBにあるテーブルをADOでつないで検索し、
CSV形式でファイルに出力します。
(るびまのソースを参考にしています。)
処理を続けるとメモリがどんどん増大してしまい、
メモリ不足で落ちてしまうので、プログラム自体を再帰(?)呼び出しして対応してみました。
Cygwinで実行するとうまく行くのですが
Windowsのコマンドプロンプトから実行すると
rubyのプロセスがガンガン増えて行ってしまい、メモリ不足に陥ります orz
そもそも、なぜメモリをガンガン使っていくのかを調べ切れていません・・・。
GC.start してみたり、コネクションを都度切ったりしてみましたが駄目でした。
再帰してみたらうまくいったって感じです。
require 'win32ole' require 'optparse' module Recordset def field self.Fields.Item(field).Value end def = field,value self.Fields.Item(field).Value = value end def each_record if self.EOF or self.BOF return end self.MoveFirst until self.EOF or self.BOF yield self self.MoveNext end end end def extract(table_name , connection) start_time = Time.new # 出力ファイル名 file_name = table_name + ".txt" # 実行するSQL sql = "select * from #{table_name}" # SQL実行 rs = connection.Execute(sql) # 特異メソッドを追加 rs.extend Recordset # フィールドの一覧を取得する fields = rs.Fields # フィールド名を出力 # Type # 3 : # 131 : int # 202 : char # 203 : varchar # #for field in fields # p field.Name + " : " + field.Type.to_s #end count = 1 open("#{file_name}" , "w") {|file| print file_name + " " rs.each_record {|record| print_count(count) list = Array.new for field in fields value = record[field.Name] if value.kind_of?(String) # nil が来る場合もある value = value ? value.strip : "" # 数値以外は,と改行をエスケープしてダブルクォートで囲む # ダブルクォートはもう一つダブルクォートを付けてエスケープする value = "\"" + value.gsub("\"" , "\"\"").gsub("\n" , "") + "\"" end list.push(value) end tmp = list.join(",") #puts count.to_s + " => " + tmp count += 1 file.puts tmp + "\n" } } # レコード数 : 処理時間 print ".(#{count} : #{Time.new - start_time}[s])" end def get_table_list(connection) # カタログの生成 catalog= WIN32OLE.new("ADOX.Catalog") catalog.ActiveConnection = connection # テーブルの一覧を取得する tables = catalog.Tables # 返却 return tables end def create_connection(file_name) connection= WIN32OLE.new("ADODB.Connection") connstr = "DRIVER={Microsoft Access Driver (*.mdb)};Dbq=#{file_name}" connection.Open connstr return connection end def print_count(count) # ログ出力 if(count % 5000 == 0) print count $stdout.flush elsif(count % 500 == 0) print "|" $stdout.flush elsif(count % 100 == 0) print "." $stdout.flush end end # 引数を格納するマップ ProgramConfig = Hash.new # 引数の判定 opts = OptionParser.new opts.on("-t table_name") {|val| ProgramConfig[:t] = val} opts.on("-i count") {|val| ProgramConfig[:i] = val} opts.parse!(ARGV) file_name = "mdbのファイル名" # コネクションの生成 connection = create_connection(file_name) # テーブルの一覧を取得する tables = get_table_list(connection) # テーブルごとにファイルを生成していく i = 0 tables_count = tables.Count for i in 0...tables_count # Item(i) の戻り値は Table table_name = tables.Item(i).Name # 開始対象のテーブル名が指定されている場合 if ProgramConfig[:t] && ProgramConfig[:t] > table_name next elsif ProgramConfig[:i] && ProgramConfig[:i].to_i > i next end # MSys始まりのテーブルは無視 if table_name =~ /^[^(MSys)]/ # ファイルに抽出する print "#{i} " extract(table_name , connection) break; end end # コネクションを閉じる connection.close puts " (#{i} / #{tables_count - 1})" if i < tables_count - 1 # 再帰(?)呼び出し exec("ruby access-mdb.rb -i #{i + 1}") else # プログラム終了 puts "The program ended." end