我有一组文件,我必须从传统COBOL系统下载这些文件每晚。我将这些文件从二进制数据文件转换为mysql表。
我写了一个Ruby程序,可以使用Bindata为个人进行此操作文件结构。每个文件中都有几个字段包装的十进制数据(COBOL COMP-3)。以下代码在读取一个代码方面起作用我的二进制文件,我编写了代码将字段amt1
转换为浮点十进制场。
此代码的问题是,对于每个包装字段,我必须重复现场转换的代码,甚至更糟的硬码十进制位置的数量对于代码中的每个字段(请参阅程序中的注释代码)。
代码的示例:
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
?
实际上,我不能因为回答我的问题而受到赞誉,但要感谢" bindata"的创建者狄翁·门德尔(Dion Mendel)在Ruby Forge的支持中回答了这个问题。我昨晚在芝加哥午夜近夜提出了这个问题,今天早上醒来,从大约3个小时后回答了Dion Mendel的答案。我想与社区分享他的答案并显示工作代码。
require 'bindata'
require 'bigdecimal'
class PkdDec < BinData::Primitive
mandatory_parameter :length
default_parameter :dec_pos => 0
string :str, :read_length => :length
def get
str_length = eval_parameter(:length)
dec_pos = eval_parameter(:dec_pos)
unpkd_field = str.unpack("H#{str_length * 2}").first
num, sign = unpkd_field[0..-2], unpkd_field[-1]
unless sign == 'f'
num = num.insert(0, '-')
end
if dec_pos > 0
dec_amt = num.insert((dec_pos + 1) * -1, '.')
else
dec_amt = num
end
return dec_amt.to_f
end
def set(dec_val)
# Not concerned about going the other way
# Reverse the get process above
end
end
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
PkdDec :amt1, :length => 6, :dec_pos => 2
PkdDec :amt2, :length => 5, :dec_pos => 2
string :ref, :read_length => 30
string :slsmn1, :read_length => 3
string :slsmn2, :read_length => 3
string :slsmn3, :read_length => 3
PkdDec :amt3, :length => 5, :dec_pos => 2
end
wang_aropnfile = File.open('../data/wangdata/AROPNFIL.bin', 'rb')
count = 0
while !wang_aropnfile.eof?
rec = WangRec.read(wang_aropnfile)
puts "#{rec.cust_no} #{rec.doc_type} #{rec.amt1} #{rec.amt2} #{rec.amt3}"
count += 1
end
puts count
再次感谢Dion Mendel