我如何在一个文件中打包十进制和普通文本?

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

由于您使用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....

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

ASCII零x'30'应转换为EBCDIC零x'F0'。 如果尚未完成(取决于EBCDIC代码页),则在大多数EBCDIC显示屏上,x'30'不映射为有效字符。

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

所以基本上你处于输/输状态。 我建议你丢掉压缩的小数点,并用数字使用普通的ASCII字符。

压缩不应该引起你的问题,除了文件传输工具可能在纯文本文件上对EBCDIC执行ASCII操作,而不是压缩文件。


“......转换成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内容是什么。 从那里你应该能够弄清楚你需要跳过什么样的箍和循环才能完成这项工作。

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

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

  • 数字存储在错误的半字节中。 数字应该在低4位中可见。 如果它位于高4位,那肯定是一个问题。
  • 非数字半字节(高4位)不包含HEX'F'或有效符号值。 无符号数字在字节的高4位总是包含HEX'F'。 如果数字是有符号的(例如,PIC S9(4)等),则最低有效数字(最后一个)的高4位应该包含HEX'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日为您的问题添加了HEX显示。 我想也许有一些格式问题。 如果这是您试图展示的内容,则以下讨论可能对您有所帮助:

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

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

  • 210003166在Zoned Decimal中
  • COMP-3中的000000002765000
  • 这是IBM大型机所期待的:

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

    注意你和上面的区别:

  • 显示器中Zoned Decimal数据的高4位包含HEX'3',它们应该包含HEx'F'。 低4位包含期望的数字。 得到那些高4位固定,你应该很好去。 顺便说一句...它在我看来,无论你试图划定十进制的'转换'是没有任何影响。 Zoned Decimal中每个数字的位模式对应于ASCII字符集中的数字。
  • 在COMP-3字段中,您指出前导零可能被截断。 对不起,但他们是数字的一部分,或者他们不是! 我上面的显示包括前导零。 您的显示器似乎已经截断了前导零,然后用空格填充了尾随字节(HEX 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指出你的名字是.benjaminjwhite.zdecimal,这看起来好像它有你需要的所有Java类来转换你的数据。 StringToZone方法应该能够将您从Oracle获取的IDENTIFIER字符串转换为字节数组,然后将其附加到输出文件。

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

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

    顺便说一句...你可以拿起这个Java工具类的源代码:http://www.benjaminjwhite.name/zdecimal

    链接地址: http://www.djcxy.com/p/41285.html

    上一篇: How can I have Packed decimal and normal text in a single file?

    下一篇: Android Market Filter Help Needed