Unpacking COMP-3 digit using Java

女生的网名这么多〃 提交于 2019-12-08 04:54:47

问题


I have a file with some COMP-3 encoded fields. Can someone please tell me how do I test this code in below thread ?

How to unpack COMP-3 digits using Java?

Code I tried is

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;
        }

Above code is not giving correct result. I tried single column to convert but it is not returning correct result. My input column

input file looks like

I tried out JRecord passing cbl copybook and data file, it generate Java Code which is giving not same result Generated output

required output

cbl copy book is look like below image


回答1:


The accepted answer might in How to unpack COMP-3 digits using Java? work if working with Ascii based Cobol. It will not work when reading Mainframe Ebcdic files with a FileReader.

You have marked the question is marked as Mainframe - Ebcdic.

To process correctly,

  1. Do a Binary transfer from the Mainframe (or run on the mainframe). Do not do an ascii conversion, this will corrupt the comp-3 fields.
  2. Read the file as a stream and process it as bytes.

The answer in COMP-3 data unpacking in Java (Embedded in Pentaho) will work; there are other answers on stackoverflow that will work as well.

Trying to process Comp-3 data as a character is error prone


JRecord

If you have a Cobol copybook, the JRecord library will let you read the file using a Cobol copybook. It contains a document ReadMe_NewUsers.html that goes through the basics.

RecordEditor

The Generate >>> Java~JRecord code for cobol menu option of the RecordEditor will generate Java~JRecord from a Cobol copybook (and optionally a data file).

There are details on generating code in this answer How do I identify the level of a field in copybook using JRecord in Java? or look at here

Also in the RecordEditor the Record Layouts >>> Load Cobol Copybook will load a Cobol copybook; you can then use the Layout to view the file.




回答2:


The best way to manipulate packed decimal is to use the IBM Data Access Accelerator API. It uses an IBM specific JVM optimization called packed objects which is a technology for efficiently working on native data. There's some good Java code on SO for processing packed decimal data but the Data Access Accelerator is the sensible choice. It blows the RYO code away.




回答3:


If you compare the copybook with the data; you will see it does not match.

In particular Class-Order-edg is defines as pic 9(3) but it looks like it is binary in the file.

Bils-count-edg looks to be shifted 6 bytes. This is consistent with fields Class-order-edg --> Country-no-edg being changed to comp-3/comp. The copybook appears to be out of date.




回答4:


The meaning of the term "COMP-3 encrypted file" is not clear to me, but I think you are saying that you have a file that was transferred from a zOS (EBCDIC) based system to an ASCII based system and you want to be able to process the values contained in the COMP-3 (packed decimal fields). If that is correct, I have some code and research that is relevant to your need.

I am assuming that the file was converted from EBCDIC to ASCII when it was transferred from zOS.

It is a common misconception that if COMP-3 (packed decimal) data is converted from EBCDIC to ASCII that it gets "corrupted". That is not the case. What you get are values ranging from x'00' - x'0F'. Regardless of whether you are are on an EBCDIC or ASCII based system, the hexadecimal values in that range are the same.

If the data is viewed outside of a hex editor [on either system] it appears to be corrupt. Depending on the code page, the packed decimal number 01234567890 may display as ⌁杅ྉ. However, using a hex editor you can see that the value is actually x'01 23 45 67 89 0F'. Two numbers are stored in a single byte (one digit in each nibble with the last nibble in the last byte being the sign). When each byte is converted from hex the actual numbers are returned. For example, using Lua, if the variable iChar contains x'23', the function oDec = string.format("%X", iChar) returns the text value of "23" which can be converted to a number. By iterating over the entire string of x'01 23 45 67 89 0F' the actual number (01234567890) is returned. The number can be "repacked" by reversing the process.

Sample code to unpack a packed decimal field is shown below:

--[[ 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()


来源:https://stackoverflow.com/questions/45567511/unpacking-comp-3-digit-using-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!