I have a group of files which I have to download from a legacy Cobol system each night. I convert these files from binary data files into MySql tables.
I wrote a Ruby program to do this using BinData for the individual
file structures. There are several fields in each of the files which contain
packed decimal data (Cobol COMP-3). The following code works in reading one
of the binary files and I wrote code to convert the field amt1
to
a floating point decimal field.
The problem with this code is that for each packed field I must repeat the code for field conversion and even worse hard code the number of decimal places for each field into the code (see the commented code in program).
Example of code:
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
How do I create my own data type primitive called pkddec
, which takes a read_length
and dec_pos
parameter and create a class PackedDecimal << BinData ::Primitive
?