Как я могу упаковать десятичный и обычный текст в одном файле?

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

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


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

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

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

Буква "А" в первом ряду имеет небольшой акцент, поэтому это не фактический верхний регистр А.

210003166 - это сырое десятичное число. Значение упакованного десятичного числа перед преобразованием comp3 равно 000000002765000 (при необходимости мы можем игнорировать начальные нули).


ОБНОВЛЕНИЕ 2: 7 июня 2011 г. Вот как я конвертирую создание файла, который загружается в мэйнфрейм: Файл содержит два столбца - Идентификационный номер и количество. Идентификационный номер не требует преобразования 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 ответа

Решение

Поскольку вы кодируете на 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....

"... преобразовано в 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 (однобайтовый набор символов).

ОБНОВЛЕНИЕ 2

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

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

Вы отметили, что это отображение двух "чисел":

  • 210003166 в десятичной зоне
  • 000000002765000 в КОМП-3

Вот что ожидает мэйнфрейм IBM:

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

Обратите внимание на различия между тем, что у вас есть, и выше:

  • Верхние 4 бита данных Zoned Decimal на вашем дисплее содержат 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, и в результате будет получена эквивалентная цифра без знака Zoned Decimal 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 хранятся внутри как Unicode-символы длиной 16 бит. Символы EBCDIC, которые вы пытаетесь создать, имеют длину всего 8 бит. Учитывая это, вам может быть лучше записать в выходной файл, используя байтовые массивы (в отличие от строк). Просто догадка от не Java-программиста.

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

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

"Они смогли получить упакованные десятичные столбцы без каких-либо проблем, но обычные числовые поля, похоже, испортились", похоже, указывают на то, что они не переводили ASCII в EBCDIC.

Ноль ASCII x'30'должен переводиться в ноль EBCDIC x'F0'. Если это не было сделано, то (в зависимости от кодовой страницы EBCDIC) x'30'не отображается на действительный символ на большинстве дисплеев EBCDIC.

Однако, даже если они перевели, у вас будут другие проблемы, так как все или некоторые из ваших данных COMP-3 будут повреждены. Простые программы перевода не имеют возможности различить символ и comp-3, поэтому они преобразуют число, такое как x'00303C', в x'00F06E', что заставит любую программу мэйнфрейма разорваться с ужасным "0C7 десятичным арифметическим исключением" (культурно эквивалентно "Stackru").

Таким образом, в основном вы находитесь в ситуации проигрыша / проигрыша. Я бы посоветовал вам отказаться от упакованных десятичных знаков и использовать простые цифры ASCII для своих чисел.

Сжатие не должно вызывать проблем, за исключением того, что утилита передачи файлов, вероятно, выполняла ASCII в EBCDIC для простого текстового файла, но не для заархивированного файла.

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

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

Если вместо "0123456789" они видят "òóôõö øù", то они просматривают символы EBCDIC в средстве просмотра с использованием ANSI или расширенного ASCII.

Другие вопросы по тегам