レガシー COBOL システムから毎晩ダウンロードしなければならないファイルのグループがあります。これらのファイルをバイナリ データ ファイルから MySql テーブルに変換します。
個々のファイル構造に BinData を使用してこれを行う Ruby プログラムを作成しました。各ファイルには、パック 10 進数データ (COBOL COMP-3) を含むいくつかのフィールドがあります。amt1
次のコードはバイナリ ファイルの 1 つを読み取る際に機能し、フィールドを浮動小数点 10 進フィールドに変換するコードを書きました。
このコードの問題は、パックされたフィールドごとにフィールド変換のコードを繰り返さなければならず、さらに悪いことに、各フィールドの小数点以下の桁数をコードにハードコーディングする必要があることです (プログラム内のコメント付きコードを参照)。
コードの例:
require 'bindata'
require 'bigdecimal'
class WangRec < BinData::Record
string :cust_no, :read_length => 6
string :doc_date, :read_length => 6
string :doc_no, :read_length => 6
string :doc_type, :read_length => 1
string :apply_to_no, :read_length => 6
string :cust_no_alt, :read_length => 6
string :apply_to_no_alt, :read_length => 6
string :doc_due_date, :read_length => 6
string :amt1, :read_length => 6
string :amt2, :read_length => 5
string :ref, :read_length => 30
string :slsmn1, :read_length => 3
string :slsmn2, :read_length => 3
string :slsmn3, :read_length => 3
string :amt3, :read_length => 5
end
def packed(packed_field, dec_pos)
unpkd_field = packed_field.unpack('H12')
num, sign = unpkd_field[0][0..-2], unpkd_field[-1]
unless sign == 'f'
amt = num.insert(0, '-')
end
if dec_pos > 0
dec_amt = amt.insert((dec_pos + 1) * -1, '.')
end
return dec_amt.to_f
end
wang_aropnfile = File.open('../data/wangdata/AROPNFIL.bin', 'rb')
count = 0
while !wang_aropnfile.eof?
rec = WangRec.read(wang_aropnfile)
# The following line of code would have to be repeated for each
# packed field along with the decimal places
amt1 = packed(rec.amt1, 2)
puts "#{rec.cust_no} #{rec.doc_type} #{rec.doc_date} #{amt1}"
count += 1
end
puts count
とパラメータpkddec
を取り、を作成するという独自のデータ型プリミティブを作成するにはどうすればよいですか?read_length
dec_pos
class PackedDecimal << BinData ::Primitive