如何在单个文件中包含打包的十进制和普通文本?

发布于 2024-11-11 18:29:06 字数 5797 浏览 14 评论 0原文

我需要生成一个固定宽度的文件,其中包含很少的压缩十进制格式的列和很少的正常数字格式的列。我能够生成。我压缩了该文件并将其传递给大型机团队。他们导入它并解压缩该文件并转换为 EBCDIC。他们能够毫无问题地获取压缩的十进制列,但正常的数字字段似乎已经混乱并且无法读取。在将文件发送到大型机之前处理/压缩文件时,我需要做一些具体的事情吗?我正在使用 COMP3 压缩十进制。目前正在 Windows XP 上工作,但真正的生产将在 RHEL 上进行。

预先感谢您帮助我。这很紧急。


编辑于 2011 年 6 月 6 日:

这就是我打开 HEX 时的样子。

. . . . . . . . . . A . .
333333333326004444
210003166750C0000

第一行中的“A”有轻微的重音,因此它不是实际的大写 A。210003166

是原始十进制。 comp3 转换之前的压缩十进制值为 000000002765000(如果需要,我们可以忽略前导零)。


更新 2:2011 年 6 月 7 日 这就是我如何转换创建加载到主机中的文件: 文件包含两列 - 标识号和名称数量。识别号不需要comp3转换,金额需要comp3转换。 Comp3转换是在oracle sql端进行的。下面是执行转换的查询:

Select nvl(IDENTIFIER,' ') as IDENTIFIER, nvl(utl_raw.cast_to_varchar2(comp3.convert(to_number(AMOUNT))),'0') as AMOUNT from TABLEX where IDENTIFIER = 123456789

执行查询后,我在 Java 中执行以下操作:

String query = "Select nvl(IDENTIFIER,' ') as IDENTIFIER, nvl(utl_raw.cast_to_varchar2(comp3.convert(to_number(AMOUNT))),'0') as AMOUNT from TABLEX where IDENTIFIER = 210003166"; // this is the select query with COMP3 conversion


ResultSet rs = getConnection().createStatement().executeQuery(sb.toString());
sb.delete(0, sb.length()-1);
StringBuffer appendedValue = new StringBuffer (200000);
while(rs.next()){
appendedValue.append(rs.getString("IDENTIFIER"))
.append(rs.getString("AMOUNT"));
}


File toWriteFile = new File("C:/transformedFile.txt");
FileWriter writer = new FileWriter(toWriteFile, true);
writer.write(appendedValue.toString());
//writer.write(System.getProperty(ComponentConstants.LINE_SEPERATOR));
writer.flush();
appendedValue.delete(0, appendedValue.length() -1);

由此生成的文本文件由 winzip 工具手动压缩并提供给大型机团队。大型机团队将文件加载到大型机中并使用 HEXON 浏览文件。

现在,进行分区十进制高四位的转换,我应该在将其正确写入文件之前执行此操作吗?或者我要在主机端应用翻转吗?现在,我已经使用以下代码在 java 端完成了翻转:

public static String toZoned(String num) {
    if (num == null) {
        return "";
    }
    String ret = num.trim();

    if (num.equals("") || num.equals("-") || num.equals("+")) {
        // throw ...
        return "";
    }

    char lastChar = ret.substring(ret.length() - 1).charAt(0);
    //System.out.print(ret + " Char - " + lastChar);
    if (lastChar < '0' || lastChar > '9') {
    } else if (num.startsWith("-")) {
        if (lastChar == '0') {
            lastChar = '}';
        } else {
            lastChar = (char) (lastChar + negativeDiff);
        }
        ret = ret.substring(1, ret.length() - 1) + lastChar;

    } else  {
        if (num.startsWith("+")) {
            ret = ret.substring(1);
        }

        if (lastChar == '0') {
            lastChar = '{';
        } else {
            lastChar = (char) (lastChar + positiveDiff);
        }
        ret = ret.substring(0, ret.length() - 1) + lastChar;
    }
    //System.out.print(" - " + lastChar);

    //System.out.println(" -> " + ret);
    return ret;
}

标识符在 java 端变成 21000316F,这就是写入文件的内容。我已将文件传递给大型机团队并等待 HEXON 的输出。如果我遗漏了什么,请告诉我。谢谢。


更新 3:2011 年 6 月 9 日

好的,我已经得到了大型机结果。我现在正在做这个。

 public static void main(String[] args) throws FileNotFoundException {
            // TODO Auto-generated method stub
            String myString = new String("210003166");
            byte[] num1 = new byte[16];
            try {
                PackDec.stringToPack("000000002765000",num1,0,15);
                System.out.println("array size: " + num1.length);
            } catch (DecimalOverflowException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } catch (DataException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } 
            byte[] ebc = null;
            try {
                ebc = myString.getBytes("Cp037");
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            PrintWriter pw = new PrintWriter("C:/transformationTextV1.txt");
            pw.printf("%x%x%x%x%x%x%x%x%x",ebc[0],ebc[1],ebc[2],ebc[3],ebc[4], ebc[5], ebc[6], ebc[7], ebc[8]);
            pw.printf("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x",num1[0],num1[1],num1[2],num1[3],num1[4], num1[5], num1[6], num1[7],num1[8], num1[9],num1[10], num1[11],num1[12], num1[13], num1[14],num1[15]);
            pw.close();
        }

我得到以下输出:

Á.Á.Á.Á.Á.Á.Á.Á.Á.................Ä
63636363636363636333333333333333336444444444444444444444444444444444444444444444
62616060606361666600000000000276503000000000000000000000000000000000000000000000

我一定做错了什么!

更新 4:2011 年 6 月 14 日

在使用 James 的建议后,此查询已得到解决。我目前正在使用下面的代码,它给了我预期的输出:

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String myString = new String("210003166");
        byte[] num1 = new byte[16];
        try {
            PackDec.stringToPack("02765000",num1,0,8);
        } catch (DecimalOverflowException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (DataException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } 
        byte[] ebc = null;
        try {
            ebc = myString.getBytes("Cp037");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        FileOutputStream writer = new FileOutputStream("C:/transformedFileV3.txt");
        writer.write(ebc,0,9);
        writer.write(num1,0,8);
        writer.close();
    }

I need to generate a fixed width file with few of the columns in packed decimal format and few of the columns in normal number format. I was able to generate. I zipped the file and passed it on to the mainframe team. They imported it and unzipped the file and converted to EBCDIC. They were able to get the packed decimal columns without any problem but the normal number fields seemed to have messed up and are unreadable. Is there something specific that I need to do while process/zip my file before sending it to mainframe? I am using COMP3 packed decimal. Currently working on Windows XP but the real production will be on RHEL.

Thanks in advance for helping me out. This is urgent.


Edited on 06 June 2011:

This is how it looks when I switch on HEX.

. . . . . . . . . . A . .
333333333326004444
210003166750C0000

The 'A' in the first row has a slight accent so it is not the actual upper case A.

210003166 is the raw decimal. The value of the packed decimal before comp3 conversion is 000000002765000 (we can ignore the leading zeroes if required).


UPDATE 2 : 7th June 2011
This how I am converting creating the file that gets loaded into the mainframe:
File contains two columns - Identification number & amount. Identification number doesn't require comp3 conversion and amount requires comp3 conversion. Comp3 conversion is performed at oracle sql end. Here is the query for performing the conversion:

Select nvl(IDENTIFIER,' ') as IDENTIFIER, nvl(utl_raw.cast_to_varchar2(comp3.convert(to_number(AMOUNT))),'0') as AMOUNT from TABLEX where IDENTIFIER = 123456789

After executing the query, I do the following in Java:

String query = "Select nvl(IDENTIFIER,' ') as IDENTIFIER, nvl(utl_raw.cast_to_varchar2(comp3.convert(to_number(AMOUNT))),'0') as AMOUNT from TABLEX where IDENTIFIER = 210003166"; // this is the select query with COMP3 conversion


ResultSet rs = getConnection().createStatement().executeQuery(sb.toString());
sb.delete(0, sb.length()-1);
StringBuffer appendedValue = new StringBuffer (200000);
while(rs.next()){
appendedValue.append(rs.getString("IDENTIFIER"))
.append(rs.getString("AMOUNT"));
}


File toWriteFile = new File("C:/transformedFile.txt");
FileWriter writer = new FileWriter(toWriteFile, true);
writer.write(appendedValue.toString());
//writer.write(System.getProperty(ComponentConstants.LINE_SEPERATOR));
writer.flush();
appendedValue.delete(0, appendedValue.length() -1);

The text file thus generated is manually zipped by a winzip tool and provided to the mainframe team. Mainframe team loads the file into mainframe and browses the file with HEXON.

Now, coming to the conversion of the upper four bits of the zoned decimal, should I be doing it before righting it to the file? Or am I to apply the flipping at the mainframe end? For now, I have done the flipping at java end with the following code:

public static String toZoned(String num) {
    if (num == null) {
        return "";
    }
    String ret = num.trim();

    if (num.equals("") || num.equals("-") || num.equals("+")) {
        // throw ...
        return "";
    }

    char lastChar = ret.substring(ret.length() - 1).charAt(0);
    //System.out.print(ret + " Char - " + lastChar);
    if (lastChar < '0' || lastChar > '9') {
    } else if (num.startsWith("-")) {
        if (lastChar == '0') {
            lastChar = '}';
        } else {
            lastChar = (char) (lastChar + negativeDiff);
        }
        ret = ret.substring(1, ret.length() - 1) + lastChar;

    } else  {
        if (num.startsWith("+")) {
            ret = ret.substring(1);
        }

        if (lastChar == '0') {
            lastChar = '{';
        } else {
            lastChar = (char) (lastChar + positiveDiff);
        }
        ret = ret.substring(0, ret.length() - 1) + lastChar;
    }
    //System.out.print(" - " + lastChar);

    //System.out.println(" -> " + ret);
    return ret;
}

The identifier becomes 21000316F at the java end and that is what gets written to the file. I have passed on the file to mainframe team and awaiting the output with HEXON. Do let me know if I am missing something. Thanks.


UPDATE 3: 9th Jun 2011

Ok I have got mainframe results. I am doing this now.

 public static void main(String[] args) throws FileNotFoundException {
            // TODO Auto-generated method stub
            String myString = new String("210003166");
            byte[] num1 = new byte[16];
            try {
                PackDec.stringToPack("000000002765000",num1,0,15);
                System.out.println("array size: " + num1.length);
            } catch (DecimalOverflowException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } catch (DataException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } 
            byte[] ebc = null;
            try {
                ebc = myString.getBytes("Cp037");
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            PrintWriter pw = new PrintWriter("C:/transformationTextV1.txt");
            pw.printf("%x%x%x%x%x%x%x%x%x",ebc[0],ebc[1],ebc[2],ebc[3],ebc[4], ebc[5], ebc[6], ebc[7], ebc[8]);
            pw.printf("%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x",num1[0],num1[1],num1[2],num1[3],num1[4], num1[5], num1[6], num1[7],num1[8], num1[9],num1[10], num1[11],num1[12], num1[13], num1[14],num1[15]);
            pw.close();
        }

And I get the following output:

Á.Á.Á.Á.Á.Á.Á.Á.Á.................Ä
63636363636363636333333333333333336444444444444444444444444444444444444444444444
62616060606361666600000000000276503000000000000000000000000000000000000000000000

I must be doing something very wrong!

UPDATE 4: 14th Jun 2011

This query was resolved after using James' suggestion. I am currently using the below code and it gives me the expected output:

    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String myString = new String("210003166");
        byte[] num1 = new byte[16];
        try {
            PackDec.stringToPack("02765000",num1,0,8);
        } catch (DecimalOverflowException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (DataException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } 
        byte[] ebc = null;
        try {
            ebc = myString.getBytes("Cp037");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        FileOutputStream writer = new FileOutputStream("C:/transformedFileV3.txt");
        writer.write(ebc,0,9);
        writer.write(num1,0,8);
        writer.close();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

在梵高的星空下 2024-11-18 18:29:06

当您使用 Java 进行编码并且需要在输出中混合使用 EBCDIC 和 COMP-3 时,您需要在自己的程序中进行 unicode 到 EBCDIC 的转换。

您不能将其留给文件传输实用程序,因为它会损坏您的 COMP-3 字段。

但幸运的是,您使用的是 Java,因此使用 string 类的 getBytes 方法很容易。

工作示例:

package com.tight.tran;

import java.io.*;

import name.benjaminjwhite.zdecimal.DataException;
import name.benjaminjwhite.zdecimal.DecimalOverflowException;
import name.benjaminjwhite.zdecimal.PackDec;

public class worong {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String myString = new String("210003166");
        byte[] num1 = new byte[16];
        try {
            PackDec.stringToPack("000000002765000",num1,0,15);
            System.out.println("array size: " + num1.length);
        } catch (DecimalOverflowException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (DataException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } 
        byte[] ebc = null;
        try {
            ebc = myString.getBytes("Cp037");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        FileOutputStream writer = new FileOutputStream("C:/transformedFile.txt");
        writer.write(ebc,0,9);
        writer.write(num1,0,15);
        writer.close();
    }

}

产生(对我来说!):

0000000: f2f1 f0f0 f0f3 f1f6 f600 0000 0000 0000  ................
0000010: 0000 0000 2765 000c 0d0a                 ....'e....

As you are coding in Java and you require a mix of EBCDIC and COMP-3 in your output you wiil need to do the unicode to EBCDIC conversion in your own program.

You cannot leave this up to the file transfer utility as it will corrupt your COMP-3 fields.

But luckily you are using Java so its easy using the getBytes method of the string class..

Working Example:

package com.tight.tran;

import java.io.*;

import name.benjaminjwhite.zdecimal.DataException;
import name.benjaminjwhite.zdecimal.DecimalOverflowException;
import name.benjaminjwhite.zdecimal.PackDec;

public class worong {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        String myString = new String("210003166");
        byte[] num1 = new byte[16];
        try {
            PackDec.stringToPack("000000002765000",num1,0,15);
            System.out.println("array size: " + num1.length);
        } catch (DecimalOverflowException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (DataException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } 
        byte[] ebc = null;
        try {
            ebc = myString.getBytes("Cp037");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        FileOutputStream writer = new FileOutputStream("C:/transformedFile.txt");
        writer.write(ebc,0,9);
        writer.write(num1,0,15);
        writer.close();
    }

}

Produces (for me!):

0000000: f2f1 f0f0 f0f3 f1f6 f600 0000 0000 0000  ................
0000010: 0000 0000 2765 000c 0d0a                 ....'e....
平安喜乐 2024-11-18 18:29:06

“他们能够毫无问题地获取压缩十进制列,但正常的数字字段似乎混乱了”似乎表明他们没有将 ASCII 转换为 EBCDIC。

ASCII 零 x'30' 应转换为 EBCDIC 零 x'F0'。如果当时没有这样做(取决于 EBCDIC 代码页),则 x'30' 不会映射到大多数 EBCDIC 显示器上的有效字符。

然而,即使他们确实翻译了,您也会遇到不同的问题,因为您的全部或部分 COMP-3 数据将被损坏。简单的翻译程序无法区分字符和 comp-3,因此它们会将 x'00303C' 等数字转换为 x'00F06E',这将导致任何大型机程序因可怕的“0C7 十进制算术异常”而崩溃(在文化上相当于“StackOverflow”)。

所以基本上你处于双输的境地。我建议您放弃压缩小数并使用纯 ASCII 字符作为数字。

压缩不会给您带来问题,除非文件传输实用程序可能在纯文本文件上执行 ASCII 到 EBCDIC 操作,但不在压缩文件上执行。

"They were able to get the packed decimal columns without any problem but the normal number fields seemed to have messed up " would seem to indicate that they did not translate ASCII to EBCDIC.

ASCII zero x'30' should translate to EBCDIC zero x'F0'. If this was not done then (depending on the EBCDIC code page) then x'30' does not map to a valid character on most EBCDIC displays.

However even if they did translate you will have different problem as all or some of your COMP-3 data will be corrupted. The simple translate programs have no way to distinguish between character and comp-3 so they will convert a number such as x'00303C' to x'00F06E' which will cause any mainframe program to bomb out with the dreaded "0C7 Decimal Arithmetic Exception" ( culturally equivalent to "StackOverflow").

So basically you are in a lose/lose situation. I would suggest you ditch the packed decimals and use plain ASCII characters for your numbers.

The zipping should not cause you a problem, except, the file transfer utility was probably doing ASCII to EBCDIC on the plain text file, but, not on the zipped file.

谷夏 2024-11-18 18:29:06

“...转换为 EBCDIC...”可能是问题的一部分。

除非大型机转换过程“意识到”记录布局,否则它是
使用(即哪些列包含二进制、打包和/或字符数据),
它会把事情搞砸,因为映射过程取决于格式。

你已经表明 COMP-3 数据没问题,我愿意打赌
“转换为 EBCDIC”不执行任何操作,或者它正在执行某种操作
将所有数据从 ASCII 转换为 COMP-3 - 从而弄乱非 COMP-3 数据。

进入主机后,您应该看到以下内容:

COMP-3 - 每个字节包含 2 位数字,除了最后一位(最右边、最左)
重要的)。最不重要的
字节的高 4 位仅包含 1 个十进制数字,符号字段位于
低 4 位。每个十进制数字均以十六进制记录(例如 5 = B'0101')

分区十进制(普通数字) - 每个字节包含 1 个十进制数字。上层
四位应始终包含十六进制 F,最低最高有效位除外
字节,其中高 4 位可以包含符号,低 4 位可以包含数字。这
4 位数字以十六进制记录(例如 5 = B'0101')

您需要查看未压缩的转换数据在主机上的样子。
请某人使用“HEX ON”在主机上“浏览”您的文件,这样您就可以
查看文件的实际十六进制内容是什么。从那里你应该能够
找出你需要跳过什么类型的循环才能做到这一点
工作。

以下是一些可能对您有帮助的链接:

更新: 如果大型机人员可以看到 < em>浏览时正确数字
“HEX ON”则有两个可能的问题:

  • 数字存储在错误的半字节中。该数字应该在
    低 4 位。如果是在高4位,那肯定是有问题的。
  • 非数字半字节(高 4 位)不包含十六进制“F”或有效符号值。
    无符号数字始终在字节的高 4 位中包含十六进制“F”。如果数量
    有符号(例如 PIC S9(4) - 或类似的东西),最低的高 4 位
    最高有效数字(最后一位)应包含十六进制“C”或“D”。

以下是使用“HEX ON”进行浏览的屏幕截图:

   File  Edit  Edit_Settings  Menu  Utilities  Compilers  Test  Help            

 VIEW       USERID.TEST.DATA - 01.99                        Columns 00001 00072 
  Command ===>                                                  Scroll ===> CSR  
  ****** ***************************** Top of Data ******************************  
 000001 0123456789                                                              
        FFFFFFFFFF44444444444444444444444444444444444444444444444444444444444444  
        012345678900000000000000000000000000000000000000000000000000000000000000  
 ------------------------------------------------------------------------------   
  000002  |¬?"±°                                                              
        012345678944444444444444444444444444444444444444444444444444444444444444  
        FFFFFFFFF000000000000000000000000000000000000000000000000000000000000000  
 ------------------------------------------------------------------------------   
  000003  àíÃÏhr                                                              
        012345678944444444444444444444444444444444444444444444444444444444444444  
        012345678900000000000000000000000000000000000000000000000000000000000000   
 ------------------------------------------------------------------------------    

以“000001”、“000002”和“000003”开头的行显示“纯”文本。下面两行
它们每个都显示其上方字符的十六进制表示形式。 HEX 的第一行
显示高 4 位,第二行显示低 4 位。

  • 第 1 行包含数字“0123456789”,后跟空格(十六进制 40)。
  • 第 2 行显示垃圾,因为上半字节和下半字节被翻转。确切的傻角色
    这只是代码页选择的问题,因此不要被您所看到的内容冲昏了头脑。
  • 第 3 行显示了类似的垃圾,因为高半字节和低半字节都包含数字。

对于无符号分区十进制数,您应该看到“000001”行
在使用 EBCDIC(单字节字符集)的 IBM 大型机上。

更新 2

您于 6 月 6 日在问题中添加了十六进制显示。我想也许有
有几个格式问题。如果这是什么
如果您试图显示,以下讨论可能对您有帮助:

..........A..
33333333326004444
210003166750C0000

您注意到这是两个“数字”的显示:

  • 210003166 in Zoned Decimal
  • 000000002765000 in COMP-3

这是 IBM 大型机所期望的:

210003166    :Á :  <-- Display character  
FFFFFFFFF00002600  <-- Upper 4 bits of each byte  
2100031660000750C  <-- Lower 4 bits of each byte  

注意您所拥有的与上述之间的差异:

  • 显示中分区十进制数据的高 4 位包含
    十六进制“3”,它们应包含十六进制“F”。低 4 位包含
    预期数字。修复高 4 位
    你应该可以走了。顺便说一句......在我看来,无论你“转变”什么
    已尝试分区十进制没有任何影响。您拥有的位模式
    分区十进制中的每个数字对应于 ASCII 字符集中的数字。
  • 在 COMP-3 字段中,您指出前导零可以被截断。
    抱歉,它们要么是号码的一部分,要么不是!我上面的显示
    包括前导零。您的显示器似乎截断了前导零,然后进行了填充
    尾随字节带有空格(十六进制 40)。这不行! COMP-3 字段定义
    具有固定的位数,并且必须表示所有数字 - 这意味着前导
    需要用零来填写每个数字的高位数字。

分区十进制修复应该很容易... COMP-3 修复可能只是一个
不去掉前导零的问题(否则看起来相当不错)。

更新 3...

如何翻转 4 个高阶位?我的印象是,您可能正在通过 Java 程序进行转换。
不幸的是,我是一名 COBOL 程序员,但我会尝试一下(不要
笑)...

根据我在这里看到的,你需要做的就是获取每个 ASCII
位并将高 4 位翻转为 HEX F,结果等效
无符号分区十进制 EBCDIC 数字。尝试类似...

public static byte AsciiToZonedDecimal(byte b) {
        //flip upper 4 bits to Hex F... 
        return (byte)(b | 0xF0)
};        

将上述内容应用于每个 ASCII 数字,结果应该是无符号 EBCDIC
分区十进制数。

更新 4...

此时 James Anderson 提供的答案应该会让您走上正轨。

James 向您指出 name.benjaminjwhite.zdecimal
看起来它拥有转换数据所需的所有 Java 类。这
StringToZone 方法
应该能够将从 Oracle 返回的 IDENTIFIER 字符串转换为字节数组,然后将其附加到
输出文件。

我对 Java 不是很熟悉,但我相信 Java 字符串在内部存储为 16 位长的 Unicode 字符。 EBCDIC
您尝试创建的字符只有 8 位长。鉴于此,您最好使用字节数组(而不是字符串)写入输出文件。
只是非 Java 程序员的预感。

上述问题中的 toZoned 方法似乎只关心第一个
和字符串的最后一个字符。部分问题在于每个角色
需要转换 - 每个字节的高 4 位(可能除了最后一位)需要修补以包含十六进制 F。低 4 位包含一位数字。

顺便说一句...您可以在以下位置获取此 Java 实用程序类的源代码: http://www.benjaminjwhite.name /z十进制

"... converted to EBCDIC..." may be part of the problem.

Unless the mainframe conversion process is "aware" of the record layout it is
working with (ie. which columns contain binary, packed and/or character data),
it is going to mess something up because the mapping process is format dependant.

You have indicated the COMP-3 data are ok, I am willing to bet that either
the "converted to EBCDIC" doesn't do anything, or it is performing some sort of
ASCII to COMP-3 conversion on all of your data - thus messing up non COMP-3 data.

Once you get to the mainframe, this is what you should see:

COMP-3 - each byte contains 2 digits except the last (right most, least
significant). The least significant
byte contains only 1 decimal digit in the upper 4 bits and the sign field in the
lower 4 bits. Each decimal digit is recorded in hex (eg. 5 = B'0101')

Zoned Decimal (normal numbers) - each byte contains 1 decimal digit. The upper
four bits should always contain HEX F, except possibly the least most significant
byte where the upper 4 bits may contain the sign and the lower 4 bits a digit. The
4 bit digit is recored in hex (eg. 5 = B'0101')

You need to see what the un-zipped converted data look like on the mainframe.
Ask someone to "BROWSE" your file on the mainframe with "HEX ON" so you can
see what the actual HEX content of your file is. From there you should be able
to figure out what sort hoops and loops you need to jump through to make this
work.

Here are a couple of links that may be of help to you:

Update: If the mainframe guys can see the correct digits when browsing with
"HEX ON" then there are two possible problems:

  • Digit is stored in the wrong nibble. The digit should be visible in the
    lower 4 bits. If it is in the upper 4 bits, that is definitely a problem.
  • The non-digit nibble (upper 4 bits) does not contain HEX 'F' or valid sign value.
    Unsigned digits always contain HEX 'F' in the upper 4 bits of the byte. If the number
    is signed (eg. PIC S9(4) - or something like that), the upper 4 bits of the least
    most significant digit (last one) should contain HEX 'C' or 'D'.

Here is a bit of a screen shot of what BROWSE with 'HEX ON' should look like:

   File  Edit  Edit_Settings  Menu  Utilities  Compilers  Test  Help            

 VIEW       USERID.TEST.DATA - 01.99                        Columns 00001 00072 
  Command ===>                                                  Scroll ===> CSR  
  ****** ***************************** Top of Data ******************************  
 000001 0123456789                                                              
        FFFFFFFFFF44444444444444444444444444444444444444444444444444444444444444  
        012345678900000000000000000000000000000000000000000000000000000000000000  
 ------------------------------------------------------------------------------   
  000002  |¬?"±°                                                              
        012345678944444444444444444444444444444444444444444444444444444444444444  
        FFFFFFFFF000000000000000000000000000000000000000000000000000000000000000  
 ------------------------------------------------------------------------------   
  000003  àíÃÏhr                                                              
        012345678944444444444444444444444444444444444444444444444444444444444444  
        012345678900000000000000000000000000000000000000000000000000000000000000   
 ------------------------------------------------------------------------------    

The lines beginning with '000001', '000002' and '000003' shows 'plain' text. the two lines below
each of them show the HEX representation of the character above it. The first line of HEX
shows the upper 4 bits, the second line the lower 4 bits.

  • Line 1 contains the number '0123456789' followed by blank spaces (HEX 40).
  • Line 2 shows junk because the upper and lower nibbles are flipped. The exact silly character
    is just a matter of code page selection so do not get carried away with what you see.
  • Line 3 shows similar junk because both upper and lower nibbles contain a digit.

Line '000001' is the sort of thing you should see for unsigned zoned decimal numbers
on an IBM mainframe using EBCDIC (single byte character set).

UPDATE 2

You added a HEX display to your question on June 6th. I think maybe there
were a couple of formatting issues. If this is what
you were trying to display, the following discussion might be of help to you:

..........A..
33333333326004444
210003166750C0000

You noted that this is a display of two "numbers":

  • 210003166 in Zoned Decimal
  • 000000002765000 in COMP-3

This is what an IBM mainframe would be expecting:

210003166    :Á :  <-- Display character  
FFFFFFFFF00002600  <-- Upper 4 bits of each byte  
2100031660000750C  <-- Lower 4 bits of each byte  

Notice the differences between what you have and the above:

  • The upper 4 bits of the Zoned Decimal data in your display contain
    a HEX '3', they should contain a HEx 'F'. The lower 4 bits contain the
    expected digit. Get those upper 4 bits fixed
    and you should be good to go. BTW... it looks to me that whatever 'conversion' you
    have attempted to Zoned Decimal is having no affect. The bit patterns you have for
    each digit in the Zoned Decimal correspond to digits in the ASCII character set.
  • In the COMP-3 field you indicated that the leading zeros could be truncated.
    Sorry, but they are either part of the number or they are not! My display above
    includes leading zeros. Your display appears to have truncated leading zeros and then padded
    trailing bytes with spaces (HEX 40). This won't work! COMP-3 fields are defined
    with a fixed number of digits and all digits must be represented - that means leading
    zeros are required to fill out the high order digits of each number.

The Zoned Decimal fix should be pretty easy... The COMP-3 fix is probably just a
matter of not stripping leading zeros (otherwise it looks pretty good).

UPDATE 3...

How do you flip the 4 high order bits? I got the impression somewhere along the line that you might be doing your conversion via a Java program.
I, unfortunately, am a COBOL programmer, but I'll take a shot at it (don't
laugh)...

Based on what I have seen here, all you need to do is take each ASCII
digit and flip the high 4 bits to HEX F and the result will be the equivalent
unsighed Zoned Decimal EBCDIC digit. Try something like...

public static byte AsciiToZonedDecimal(byte b) {
        //flip upper 4 bits to Hex F... 
        return (byte)(b | 0xF0)
};        

Apply the above to each ASCII digit and the result should be an unsigned EBCDIC
Zoned Decimal number.

UPDATE 4...

At this point the answers provided by James Anderson should put you on the right track.

James pointed you to name.benjaminjwhite.zdecimal and
this looks like it has all the Java classes you need to convert your data. The
StringToZone method
should be able to convert the IDENTIFIER string you get back from Oracle into a byte array that you then append to the
output file.

I am not very familiar with Java but I believe Java Strings are stored internally as Unicode Characters which are 16 bits long. The EBCDIC
characters you are trying to create are only 8 bits long. Given this, you might be better off writting to the output file using byte arrays (as opposed to strings).
Just a hunch from a non Java programmer.

The toZoned method in your question above appears to only concern itself with the first
and last characters of the string. Part of the problem is that each and every character
needs to be converted - the 4 upper bits of each byte, except possibly the last, needs to be patched to contain Hex F. The lower 4 bits contain one digit.

BTW... You can pick up the source for this Java utility class at: http://www.benjaminjwhite.name/zdecimal

倒数 2024-11-18 18:29:06

听起来问题出在 EBCDIC 转换上。压缩十进制将使用字符作为字节值,并且不受音译 EBCDIC <-> 的限制。 ASCII。

如果他们看到控制字符(或 Windows 上的方形标记),那么他们可能正在将 ASCII 数据视为 EBCDIC。

如果他们看到“ñòóôõö øù”代替“0123456789”,那么他们正在使用 ANSI 或扩展 ASCII 的查看器中查看 EBCDIC 字符。

It sounds like the problem is in the EBCDIC conversion. The packed decimal would use characters as byte values, and isn't subject to the transliterations EBCDIC <-> ASCII.

If they see control characters (or square markers on Windows), then they may be viewing ASCII data as EBCDIC.

If they see " ñòóôõö øù" in place of "0123456789" then they are viewing EBCDIC characters in a viewer using ANSI, or extended ASCII.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文