1

我有一个包含一些 COMP-3 编码字段的文件。有人可以告诉我如何在下面的线程中测试这段代码吗?

如何使用 Java 解压缩 COMP-3 数字?

我试过的代码是

BufferedReader br = new BufferedReader(new FileReader(FILENAME))) {

    String sCurrentLine;
    int i=0;
    String bf =null;
    while ((sCurrentLine = br.readLine()) != null) {
        i++;
        System.out.println("FROM BYTES ");
            System.out.println(unpackData(sCurrentLine.getBytes(), 5));

        for (int j = 0; j < sCurrentLine.length(); j++) {
            char c = sCurrentLine.charAt(j);
            bf =bf + (int)c;
        }

上面的代码没有给出正确的结果。我尝试单列进行转换,但它没有返回正确的结果。我的输入栏 在此处输入图像描述

输入文件看起来像

在此处输入图像描述

我尝试了 JRecord 传递 cbl copybook 和数据文件,它生成的 Java 代码给出的结果不同生成的输出 在此处输入图像描述

所需输出

在此处输入图像描述

cbl 抄本如下图所示

在此处输入图像描述

4

4 回答 4

0

接受的答案可能How to unpack COMP-3 digits using Java? 如果使用基于AsciiCobol工作。使用 FileReader 读取大型机 Ebcdic文件时,它将不起作用。

您已将问题标记为Mainframe - Ebcdic

要正确处理,

  1. 从大型机执行二进制传输(或在大型机上运行)。不要进行 ascii 转换,这会损坏 comp-3 字段。
  2. 将文件作为流读取并将其作为字节处理。

COMP-3 data unpacking in Java (Embedded in Pentaho) 中的答案将起作用;stackoverflow 上还有其他答案也可以。

尝试将 Comp-3 数据作为字符处理很容易出错


记录

如果您有 Cobol 字帖,JRecord 库将允许您使用 Cobol 字帖阅读文件。它包含一个文档 ReadMe_NewUsers.html,其中包含基础知识。

记录编辑器

RecordEditor的 Cobol菜单选项的Generate >>> Java~JRecord code将从 Cobol 副本(以及可选的数据文件)生成 Java~JRecord。 在此处输入图像描述

此答案中有关于生成代码的详细信息How do I identify the level of a field in copybook using JRecord in Java? 或看这里

同样在RecordEditor中,Record Layouts >>> Load Cobol Copybook将加载 Cobol Copybook;然后您可以使用Layout来查看文件。

于 2017-08-08T12:56:50.983 回答
0

处理压缩十进制的最佳方法是使用IBM Data Access Accelerator API。它使用 IBM 特定的 JVM 优化,称为打包对象,这是一种有效处理本机数据的技术。在 SO 上有一些很好的 Java 代码用于处理打包的十进制数据,但数据访问加速器是明智的选择。它吹走了RYO代码。

于 2017-08-10T06:43:24.813 回答
0

如果字帖与数据进行比较;你会看到它不匹配。

特别是Class-Order-edg被定义为 pic 9(3)但它看起来像是文件中的二进制文件。

Bils-count-edg 看起来移动了 6 个字节。这与字段 Class-order-edg --> Country-no-edg 更改为 comp-3/comp 一致。字帖似乎已经过时了。

于 2017-08-11T11:53:54.217 回答
-1

我不清楚“COMP-3 加密文件”一词的含义,但我认为您是说您有一个文件从基于 zOS (EBCDIC) 的系统传输到基于 ASCII 的系统,并且您希望成为能够处理包含在 COMP-3(压缩十进制字段)中的值。如果这是正确的,我有一些与您的需求相关的代码和研究。

我假设文件从 zOS 传输时已从 EBCDIC 转换为 ASCII。

一个常见的误解是,如果将 COMP-3(压缩十进制)数据从 EBCDIC 转换为 ASCII,就会“损坏”。事实并非如此。你得到的是范围从 x'00' - x'0F' 的值。无论您使用的是基于 EBCDIC 还是基于 ASCII 的系统,该范围内的十六进制值都是相同的。

如果在 [任一系统上] 的十六进制编辑器之外查看数据,则它似乎已损坏。根据代码页,压缩十进制数 01234567890 可能显示为⌁杅ྉ。但是,使用十六进制编辑器可以看到该值实际上是 x'01 23 45 67 89 0F'。两个数字存储在一个字节中(每个半字节中的一个数字,最后一个字节中的最后一个半字节为符号)。当每个字节从十六进制转换时,将返回实际数字。例如,使用 Lua,如果变量 iChar 包含 x'23',则函数 oDec = string.format("%X", iChar) 返回文本值“23”,可以将其转换为数字。通过遍历 x'01 23 45 67 89 0F' 的整个字符串,返回实际数字 (01234567890)。可以通过反转过程来“重新打包”该号码。

解压压缩十进制字段的示例代码如下所示:

--[[ Lua 5.2.3 ]]
--[[ Author: David Alley 
         Written: August 9, 2017 ]]
--[[ Begin Function ]]
function xdec_unpack (iHex, lField, lNumber)
--[[
This function reads packed decimal data (converted from EBCDIC to ASCII) as input
and returns unpacked ASCII decimal numbers.
--]]
    if iHex == nil or iHex == ""
        then
            return iHex
    end             
    local aChar = {}     
    local aUnpack = {} 
    local iChar = ''
    for i = 1, lField do
        aChar[i] = string.byte(iHex, i)
    end
    for i, iChar in ipairs(aChar) do
        local oDec = string.format("%X", iChar)
            if string.len(oDec) == 1
                then
            table.insert(aUnpack, "0" .. oDec) --[[ Handles binary zeros ]]
            else
                table.insert(aUnpack, oDec)
            end
    end
    if string.len(table.concat(aUnpack)) - 1 ~= lNumber
        then
            aUnpack[1] = string.sub(aUnpack[1],2,2)
    end
return table.concat(aUnpack)
end
--[[ End Function xdec_unpack ]]

--[[ The code below was written for Linux and reads an entire file. It assumes that there is only one field, and that 
         field is in packed decimal format. Packed decimal format means that the file was transferred from a z/OS (EBCDIC) system 
         and the data was converted to ASCII.

         It is necessary to supply the field length because when Lua encounters binary zeros (common in packed decimal), 
       they are treated as an "end of record" indicator. The packed length value is supplied by the variable lField and the
         unpacked length value is supplied by the variable lNumber. 

         Since there is only one field, that field by default, is at the end of each record (the field is the record). Therefore, 
         any "new line" values (0x0a for Linux) must be included when reading records. This is handled by adding 1 to the variable 
         lField when reading records. Therefore, this code must be modified if there are multiple fields, and/or the packed decimal
         field is not the last field in the record.

         The sign is dropped from the unpacked value that is returned from the function xdec_unpack by removing the last byte from the 
         variable Output1 before writing the records. Therefore, this code must be modified if it is necessary to process negative 
         numbers. ]]

local lField = 7      --[[ This variable is the length of the packed decimal field before unpacking and is required by the 
                                                 xdec_unpack function. ]]
local lNumber = 12  --[[ This variable is the length of the unpacked decimal field not including the sign. It is required by the 
                                                 xdec_unpack function. Its purpose is to determine if a high order zero (left zero) is to be removed. This 
                                                 occurs in situations where the packed decimal field contains an even number of digits. For example,
                                                 0123456789. ]]
local sFile = io.open("/home/david/Documents/Lua/Input/Input2.txt", "r")
local oFile = io.open("/home/david/Documents/Lua/Input/Output1.txt", "w")
while true do
    sFile:seek("cur")
    local sLine = sFile:read(lField + 1)        
    if sLine == nil then break end
    local Output1 = xdec_unpack(sLine, lField, lNumber) --[[ Call function to unpack ]]
  Output1 = string.sub(Output1,1, #Output1 - 1) --[[ Remove sign ]]
    oFile:write(Output1, "\n")
end
sFile:close()
oFile:close()
于 2017-08-10T21:44:38.537 回答