2

我需要生成一个固定宽度的文件,其中包含少数压缩十进制格式的列和少数正常数字格式的列。我能够生成。我将文件压缩并传递给大型机团队。他们将其导入并解压缩文件并转换为 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();
    }
4

4 回答 4

2

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

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

但幸运的是,您使用的是 Java,因此使用字符串类的 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....
于 2011-06-06T09:14:25.383 回答
1

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

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

您已经表明 COMP-3 数据没问题,我敢打赌,“转换为 EBCDIC”没有做任何事情,或者它正在对您的所有数据执行某种 ASCII 到 COMP-3 的转换 - 因此弄乱非 COMP-3 数据。

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

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

Zoned Decimal(普通数字)- 每个字节包含 1 个十进制数字。高 4 位应始终包含 HEX F,但可能是最低有效字节,其中高 4 位可能包含符号,而低 4 位可能包含数字。4 位数字以十六进制记录(例如 5 = B'0101')

您需要查看解压缩后的转换数据在大型机上的样子。让某人使用“HEX ON”在大型机上“浏览”您的文件,这样您就可以看到文件的实际 HEX 内容是什么。从那里你应该能够弄清楚你需要跳过什么样的循环来完成这项工作。

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

更新:如果大型机人员在使用“HEX ON”浏览时可以看到正确的数字,那么可能存在两个问题:

  • 数字存储在错误的半字节中。该数字应在低 4 位中可见。如果它在高 4 位,那肯定是个问题。
  • 非数字半字节(高 4 位)不包含 HEX 'F' 或有效符号值。无符号数字在字节的高 4 位中始终包含 HEX '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”,后跟空格 (HEX 40)。
  • 第 2 行显示垃圾,因为上下半字节被翻转。确切的傻字符只是代码页选择的问题,所以不要被你看到的东西冲昏了头脑。
  • 第 3 行显示了类似的垃圾,因为上半字节和下半字节都包含一个数字。

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

更新 2

您在 6 月 6 日为您的问题添加了十六进制显示。我认为可能存在一些格式问题。如果这是您要显示的内容,那么以下讨论可能对您有所帮助:

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

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

  • 210003166 分区十进制
  • COMP-3 中的 000000002765000

这是 IBM 大型机所期望的:

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

注意你所拥有的和上面的区别:

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

Zoned Decimal 修复应该很容易...... 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 将您指向name.benjaminjwhite.zdecimal,它看起来拥有转换数据所需的所有 Java 类。StringToZone 方法 应该能够将从 Oracle 返回的 IDENTIFIER 字符串转换为字节数组,然后将其附加到输出文件中。

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

您上面问题中的toZoned方法似乎只关注字符串的第一个和最后一个字符。部分问题是每个字符都需要转换 - 每个字节的高 4 位,可能除了最后一个,需要修补以包含十六进制 F。低 4 位包含一个数字。

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

于 2011-06-02T17:16:31.643 回答
1

“他们能够毫无问题地获得压缩十进制列,但正常的数字字段似乎搞砸了”似乎表明他们没有将 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,而不是在压缩文件上。

于 2011-06-03T05:04:29.997 回答
0

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

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

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

于 2011-06-02T16:44:45.290 回答