gpt4 book ai didi

ruby - 使用 BinData 从二进制数据创建用户定义的原始类型?

转载 作者:太空宇宙 更新时间:2023-11-03 16:32:38 26 4
gpt4 key购买 nike

我有一组文件必须从遗留 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_lengthdec_pos参数并创建一个 class PackedDecimal << BinData ::Primitive

最佳答案

实际上,我不能因为回答了我的问题而受到赞扬,但非常感谢“BinData”的创建者 Dion Mendel 在 Ruby Forge 的支持中回答了这个问题。我昨晚在芝加哥时间接近午夜时提交了这个问题,今天早上醒来发现 Dion Mendel 的答案大约在 3 小时后得到了回答。我想与社区分享他的答案并展示工作代码。

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

关于ruby - 使用 BinData 从二进制数据创建用户定义的原始类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13224535/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com