Как я могу упаковать десятичный и обычный текст в одном файле? - PullRequest
2 голосов
/ 02 июня 2011

Мне нужно создать файл фиксированной ширины с несколькими столбцами в упакованном десятичном формате и несколькими столбцами в обычном числовом формате.Я был в состоянии генерировать.Я сжал файл и передал его команде мэйнфреймов.Они импортировали его, распаковали файл и конвертировали в EBCDIC.Они смогли получить упакованные десятичные столбцы без каких-либо проблем, но обычные числовые поля, похоже, испортились и не читаются.Есть ли что-то конкретное, что мне нужно сделать во время обработки / архивирования моего файла перед его отправкой на мэйнфрейм?Я использую десятичную упаковку COMP3.В настоящее время работаю над Windows XP, но реальное производство будет на RHEL.

Заранее спасибо за помощь.Это срочно.


Отредактировано 06 июня 2011 года:

Вот как это выглядит, когда я включаю HEX.

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

Символ 'A' в первой строке имеет небольшой акцент, поэтому он не является действительным верхним регистром A.

210003166 является необработанным десятичным знаком.Значение упакованного десятичного числа перед преобразованием в comp3 равно 000000002765000 (при необходимости мы можем игнорировать начальные нули.)файл, который загружается в мэйнфрейм: файл содержит два столбца - идентификационный номер и количество.Идентификационный номер не требует преобразования comp3, а сумма требует преобразования comp3.Comp3 преобразование выполняется в конце Oracle.Вот запрос для выполнения преобразования:

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

Идентификатор становится 21000316F в конце Java, и это то, что записывается в файл.Я передал файл команде мэйнфреймов и ожидаю вывода с HEXON.Дай мне знать, если я что-то упустил.Спасибо.


ОБНОВЛЕНИЕ 3: 9 июня 2011

Хорошо У меня есть результаты мэйнфреймов.Я делаю это сейчас.

 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: 14 июня 2011

Этот запрос был решен после использования предложения Джеймса.В настоящее время я использую приведенный ниже код, и он дает мне ожидаемый результат:

    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 ]

2 голосов
/ 06 июня 2011

Поскольку вы кодируете в Java и вам требуется сочетание EBCDIC и COMP-3 в выходных данных, вам потребуется выполнить преобразование Unicode в EBCDIC в вашей собственной программе.

Вы не можете оставить это на усмотрение утилиты передачи файлов, поскольку она повредит ваши поля COMP-3.

Но, к счастью, вы используете Java, так что это легко, используя метод getBytes класса string ..

Рабочий пример:

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....
1 голос
/ 02 июня 2011

«... преобразовано в EBCDIC ...» может быть частью проблемы.

Если процесс преобразования мэйнфрейма не «знает» о макете записи, с которым он работает (т.е. какие столбцы содержатдвоичные, упакованные и / или символьные данные), это может что-то испортить, потому что процесс отображения зависит от формата.

Вы указали, что данные COMP-3 в порядке, я готов поспорить, что либо«преобразовано в EBCDIC» ничего не делает, или выполняет какое-то преобразование ASCII в COMP-3 для всех ваших данных - таким образом, запутывая данные не в COMP-3.

Как только вы доберетесь домэйнфрейм, это то, что вы должны увидеть:

COMP-3 - каждый байт содержит 2 цифры, кроме последней (справа, младший, младший).Младший значащий байт содержит только 1 десятичную цифру в старших 4 битах и ​​поле знака в младших 4 битах.Каждая десятичная цифра записывается в шестнадцатеричном формате (например, 5 = B'0101 ')

Зональная десятичная дробь (нормальные числа) - каждый байт содержит 1 десятичную цифру.Старшие четыре бита должны всегда содержать HEX F, за исключением, возможно, самого младшего старшего байта, где старшие 4 бита могут содержать знак, а младшие 4 бита - цифру.4-разрядная цифра записывается в шестнадцатеричном формате (например, 5 = B'0101 ')

Вам необходимо увидеть, как выглядят преобразованные данные без сжатия на мэйнфрейме.Попросите кого-нибудь «ПРОСМОТРЕТЬ» ваш файл на мэйнфрейме с помощью «HEX ON», чтобы вы могли видеть, каково фактическое содержимое HEX вашего файла.Оттуда вы сможете выяснить, через какие обручи и петли вам нужно перейти, чтобы сделать эту работу.

Вот несколько ссылок, которые могут вам помочь:

Обновление: Если мэйнфреймРебята могут видеть правильные цифры при просмотре с помощью "HEX ON", тогда есть две возможные проблемы:

  • Цифра хранится в неправильном клеве.Цифра должна быть видна в нижних 4 битах.Если он находится в старших 4 битах, то это определенно является проблемой.
  • Недискретный полубайт (старшие 4 бита) не содержит HEX 'F' или действительного значения знака.Цифры без знака всегда содержат HEX 'F' в старших 4 битах байта.Если число подписано (например, PIC S9 (4) - или что-то в этом роде), старшие 4 бита самой младшей значащей цифры (последней) должны содержать HEX 'C' или 'D'.

Вот скриншот того, как должен выглядеть BROWSE с «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' - это то, что вы должны увидеть для зонированных десятичных чисел без знака на мэйнфрейме IBM, используя EBCDIC (однобайтовый набор символов).

UPDATE 2

Вы добавили HEX-дисплей к своему вопросу 6 июня.Я думаю, возможно, было несколько проблем с форматированием.Если это то, что вы пытались отобразить, вам может помочь следующее обсуждение:

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

Вы заметили, что это отображение двух «цифр»:

  • 210003166 в зонированном десятичном числе
  • 000000002765000 в COMP-3

Это то, что мэйнфрейм 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 ...

На этом этапе ответы Джеймса Андерсона должны направить вас на правильный путь.

Джеймс указал вам name.benjaminjwhite.zdecimal и похоже, в нем есть все классы Java, необходимые для преобразования ваших данных. Метод StringToZone должна быть в состоянии преобразовать строку IDENTIFIER, которую вы возвращаете из Oracle, в байтовый массив, который вы затем добавляете в выходной файл.

Я не очень знаком с Java, но я считаю, что строки Java хранятся внутри как символы Юникода, длина которых составляет 16 бит. EBCDIC длина символов, которые вы пытаетесь создать, составляет всего 8 бит. Учитывая это, вам может быть лучше записать в выходной файл, используя байтовые массивы (в отличие от строк). Просто догадка от не Java-программиста.

Метод toZoned в вашем вопросе, по-видимому, касается только первого и последние символы строки. Часть проблемы в том, что каждый персонаж необходимо преобразовать - 4 старших бита каждого байта, кроме, возможно, последнего, должны быть исправлены, чтобы содержать шестнадцатеричный код F. Нижние 4 бита содержат одну цифру.

Кстати ... Вы можете подобрать источник для этого служебного класса Java по адресу: http://www.benjaminjwhite.name/zdecimal

1 голос
/ 03 июня 2011

«Они смогли получить упакованные десятичные столбцы без каких-либо проблем, но обычные числовые поля, похоже, испортились», похоже, указывают на то, что они не переводили 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 для простого текстового файла, но не для заархивированного файла.

0 голосов
/ 02 июня 2011

Похоже, проблема в преобразовании EBCDIC. Упакованный десятичный знак будет использовать символы в качестве байтовых значений и не подлежит транслитерации EBCDIC <-> ASCII.

Если они видят управляющие символы (или квадратные маркеры в Windows), то они могут просматривать данные ASCII как EBCDIC.

Если вместо «0123456789» они видят «òóôõöö», то они просматривают символы EBCDIC в средстве просмотра, используя ANSI или расширенный ASCII.

...