Wie kann ich IBM Mainframe-Dateien in Java eingeben / ausgeben?

Wie kann ich IBM Mainframe-Dateien in Java eingeben / ausgeben?

Das Ein- und Aussteigen der IBM Mainframe-Dateien in Java kann etwas mühsam sein:

Als ich darüber nachdachte, ob ich es selbst machen sollte, fand ich eine sehr praktische Utility-Klasse, die als Open Source bereitgestellt wurde, und werde daher die Verwendung vorstellen. ** * Obwohl dies praktisch ist, gibt es auf Japanisch nur wenige Informationen. Es ist eine Verschwendung. ** </ font>

IBM Toolbox for Java Vom Namen her fühlt es sich wie DER Hauptrahmen an.

Installation und Einrichtung

  • Laden Sie die ZIP-Datei mit der OSS-Version der JAR-Datei (z. B. jtopen_9_3.zip) von der folgenden Download-Seite herunter.
  • Entpacken Sie die Datei "jtopen_9_3.zip", nehmen Sie die JAR-Datei "lib \ java8 \ jt400.jar" heraus und fügen Sie sie in den Klassenpfad ein.

Informationsquellen zur Programmierung usw.

Anforderungsdefinition für die Eingabe / Ausgabe von IBM Mainframe-Dateien in Java

Bevor ich das Tool vorstelle, werde ich kurz erläutern, was Sie von diesem Tool erwarten, dh die Anforderungen definieren und erläutern, wie das Tool gemäß diesen Anforderungen verwendet wird.

  1. Ich möchte die Datensatzformatdefinition definieren, die für die Eingabe / Ausgabe von Dateien im IBM Mainframe außerhalb des Java-Programms verwendet wird, und Datensätze und Elemente gemäß der Definition abgrenzen.
  2. Ich möchte auch eine Zeichencode-Konvertierung durchführen.
  3. Ich möchte die sogenannten binären Dezimalzahlen von dezimalen Pack-Dezimalzahlen und vorzeichenlosen Pack-Dezimalzahlen als Big Decimal behandeln.

Beispiel: Eingabe / Ausgabe einer IBM Mainframe-Datei in Java

Es wird davon ausgegangen, dass der folgende IBM Mainframe-Dateidatensatz in Java eingegeben / ausgegeben wird.

Niveau Name des Datenelements Schimmel Anzahl an Ziffern Richtigkeit Wiederholend Teilzeitstelle Bemerkungen
01 ORDER-REC 124 Bestelldatensatz
03 REC-NO B 4 2 Rekordzahl
03 ORDER-NO C 10 10 Bestellnummer
03 ZIP-CD C 8 8 Postleitzahl
03 ADDRESS C 20 20 Adresse(18 Bytes für IBM Kanji-Code, 20 Bytes für Shift-Code)
03 PRODUCT-GR S 3 84 Produktgruppenartikel(OCCCURS 3 mal)
05 PRODUCT-CD C 15 15 Produktcode
05 PRODUCT-AMT Z 5 2 5 Produktgewicht(Zonen-Dezimalzahl)
05 UNIT-PRC P 7 2 4 Stückpreis(Dezimal gepackt)
05 DISCOUNT-PRC P 7 2 4 Rabattbetrag(Dezimal gepackt)

Typlegende:

Schimmel Erläuterung
B Binärtyp. Wenn Sie die obige "Datensatznummer" in COBOL schreiben, wird "S9"(4) COMP-Vier ". Da es sich um eine 4-stellige Binärzahl handelt, beträgt die Anzahl der Bytes 2 Bytes.
C Zeichentyp. Wenn Sie die obige "Bestellnummer" in COBOL schreiben, "X"(10)」。
S Gruppenelement. Es bündelt mehrere Datenelemente.
P Pack Dezimaltyp. Wenn Sie den obigen "Stückpreis" in COBOL schreiben, wird "S9"(7)V9(2) COMP-3」。
Z Zonen-Dezimaltyp. Wenn das obige "Produktgewicht" in COBOL geschrieben ist, "9(5)V9(2)」。

Erläuterungen zu Zonen-Dezimalzahlen (auch als externe Dezimalzahlen und entpackte Dezimalzahlen bezeichnet) und gepackten Dezimalzahlen (interne Dezimalzahlen) finden Sie unter den folgenden URLs. https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%83%E3%82%AF10%E9%80%B2%E6%95%B0 https://www.ibm.com/support/knowledgecenter/ja/SSQ2R2_9.1.0/com.ibm.etools.cbl.win.doc/topics/cpari20e.htm#header_19

Erstellen Sie eine Datensatzformat-Definitionsdatei (RFML-Datei) und platzieren Sie sie im Klassenpfad.

Erstellen Sie eine Datensatzformat-Definitionsdatei für die Mainframe-Datei und aktivieren Sie die Eingabe und Ausgabe der Datei entsprechend. Mit IBM ToolBox für Java können Sie Dateien basierend auf RFML-Dateien im XML-Format als Definitionsdateien für das Datensatzformat eingeben und ausgeben. Machen Sie es zuerst und setzen Sie es auf den Klassenpfad. Dies dient dazu, diese Definitionsdatei später vom Java-Programm aus dem Klassenpfad abzurufen.

Die DTD für diese XML-Datei finden Sie unter Programmieren von IBM Toolbox für Java. Beachten Sie, wo "ccs id =" 930 "" steht. Es wird auf der Root-Ebene und unter "ADRESS" geschrieben. Dies gibt den Zeichencode des Hauptrahmens an. Wenn Sie jedoch den gesamten Zeichencode angeben möchten, schreiben Sie ihn auf dieser Stammebene. Wenn einzeln angegeben, kann es für jedes Datenelement angegeben werden.

ORDER-FILE.rfml(Definitionsdatei für das Mainframe-Datensatzformat)


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE rfml SYSTEM "rfml.dtd">
<rfml version="4.0" ccsid="930">
  <struct name="PRODUCT-GR">
    <data name="PRODUCT-CD" type="char" length="15"/>
    <data name="PRODUCT-AMT" type="zoned" length="5" precision="2"/>
    <data name="UNIT-PRC" type="packed" length="7" precision="2"/>
    <data name="DISCOUNT-PRC" type="packed" length="7" precision="2"/>
  </struct>
  <recordformat name="ORDER01-REC">
    <data name="REC-NO" type="int" length="2"/>
    <data name="ORDER-NO" type="char" length="10"/>
    <data name="ZIP-CD" type="char" length="8"/>
    <data name="ADRESS" type="char" length="20" ccsid="930"/>
    <data name="PRODUCT-GR" type="struct" struct="PRODUCT-GR" count="3"/>
  </recordformat>
</rfml>

Hauptframe-Dateiausgabe Teil 1 (Fehlerbeispiel)

Das Folgende ist ein Beispiel für einen Fehler. Struktur und Array werden nicht unterstützt. Mit anderen Worten, Gruppenelemente und OCCURS können nicht verwendet werden. was ist zu tun?

Ausgabe der Hauptbilddatei Teil 1(Fehlerbeispiel)


    /**
     *Ausgabe der Hauptbilddatei. <BR>
     *Gibt die Mainframe-Datei gemäß der Datensatzformatdefinition der RFML-Datei aus.<BR>
     * {@code
      rec.setField("PRODUCT-GR", null);}An dem Ort{@code
    com.ibm.as400.access.ExtendedIllegalArgumentException: name (PRODUCT-GR): Field was not found.
    }<BR>
     *Ich bekomme eine Ausnahme. In der folgenden API-Dokumentation wird angegeben, dass Structure nicht unterstützt wird. Array wird ebenfalls nicht unterstützt.<BR>
     * <a href=
     * "https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzahh/javadoc/com/ibm/as400/data/RecordFormatDocument.html">
     * https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzahh/javadoc/com/ibm/as400/data/RecordFormatDocument.html</a>
     */
    @Test
    public void test01MfFileOutput() {
        //Suchen und lesen Sie die Datensatzformatdefinition im Klassenpfad.
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument("jp.golden.cat.util.ORDER-FILE.rfml");
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }

        //Dateiausgabe mit Hauptrahmenzeichencode.
        File ioFile = new File("./data/ORDER_FILE.dat");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            Record rec = rfd.toRecordFormat("ORDER01-REC").getNewRecord();
            for (short i = 1; i < 11; i++) {
                rec.setField("REC-NO", new Short(i));
                rec.setField("ORDER-NO", "170423-123");
                rec.setField("ZIP-CD", "103-0028");
                rec.setField("ADRESS", "Yaesu, Chuo-ku, Tokio");
                //↓ Hier tritt eine Ausnahme auf, also kommentieren Sie aus.
                // rec.setField("PRODUCT-GR", null);
                //Byte-Array und Ausgabe in Datei.
                byte[] buf = rec.getContents();
                StringUtil.dump("DEBUG:", buf, "");
                fos.write(buf);
            }
            fos.flush();
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

Ausgabe der Hauptbilddatei Teil 2 (Erfolgsbeispiel)

Gruppenelemente und OCCURS können nicht verwendet werden. Gehen Sie daher wie folgt vor.

  1. Gruppenelemente und OCCURS verhalten sich nicht wie beabsichtigt. Betrachten Sie diesen Teil daher als ein Einzelbyte-Array.
  2. Definieren Sie den Gruppenelementteil in einer anderen Datensatzformatdefinition und legen Sie dort ein Java-Objekt fest, um ein Byte-Array mit MF-Zeichencode zu erstellen.
    1. Stellen Sie die obigen 2 auf die obigen 1 ein.

ORDER-FILE.rfml(Definitionsdatei für das Mainframe-Datensatzformat. Der Gruppenelementteil hat eine andere Datensatzdefinition.)


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE rfml SYSTEM "rfml.dtd">
<rfml version="4.0" ccsid="930">
  <recordformat name="PRODUCT-GR">
    <data name="PRODUCT-CD" type="char" length="15"/>
    <data name="PRODUCT-AMT" type="zoned" length="5" precision="2"/>
    <data name="UNIT-PRC" type="packed" length="7" precision="2"/>
    <data name="DISCOUNT-PRC" type="packed" length="7" precision="2"/>
  </recordformat>
  <recordformat name="ORDER01-REC">
    <data name="REC-NO" type="int" length="2"/>
    <data name="ORDER-NO" type="char" length="10"/>
    <data name="ZIP-CD" type="char" length="8"/>
    <data name="ADRESS" type="char" length="20" ccsid="930"/>
    <data name="PRODUCT-B" type="byte" length="84"/>
  </recordformat>
</rfml>

Ausgabe der Hauptbilddatei Teil 2(Erfolgsgeschichte)


    /**
     *Ausgabe der Hauptbilddatei. <BR>
     *Gibt die Mainframe-Datei gemäß der Datensatzformatdefinition der RFML-Datei aus.<BR>
     * 1.Da sich das Gruppenelement und OCCURS nicht wie beabsichtigt verhalten, wird dieser Teil als Byte-Array betrachtet.<BR>
     * 2.Definieren Sie den Gruppenelementteil in einer anderen Datensatzformatdefinition und legen Sie dort ein Java-Objekt fest, um ein Byte-Array mit MF-Zeichencode zu erstellen.<br>
     *3. 3. Über 2 über 1.Einstellen.
     */
    @Test
    public void test02MfFileOutput() {
        //Suchen und lesen Sie die Datensatzformatdefinition im Klassenpfad.
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument("jp.golden.cat.util.ORDER-FILE.rfml");
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }

        //Dateiausgabe mit Hauptrahmenzeichencode.
        File ioFile = new File("./data/ORDER_FILE.dat");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            Record rec = rfd.toRecordFormat("ORDER01-REC").getNewRecord();
            Record grp = rfd.toRecordFormat("PRODUCT-GR").getNewRecord();
            for (int i = 1; i < 11; i++) {
                rec.setField("REC-NO", new Short((short) i));
                rec.setField("ORDER-NO", "170423-123");
                rec.setField("ZIP-CD", "103-0028");
                rec.setField("ADRESS", "Yaesu, Chuo-ku, Tokio");

                //Der Code für den OCCURS-Teil des Gruppenelements.
                //Ein Bytestrom des gesamten Gruppenelements, an das das Element übertragen wird.
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                //Bytelänge des Ziels für die Elementübertragung ÷ 1 Bytelänge für OCCURS(PRODUCT-GR)= Anzahl der OCCC-URS
                int occursCount = rec.getFieldAsBytes("PRODUCT-B").length / grp.getRecordLength();
                //OCCURS Wiederholen Sie dies einige Minuten lang
                for (int j = 0; j < occursCount; j++) {
                    grp.setField("PRODUCT-CD", "ABCDEFGHIJ-000" + j);
                    grp.setField("PRODUCT-AMT", new BigDecimal("123.45"));
                    grp.setField("UNIT-PRC", new BigDecimal("+12345.67"));
                    grp.setField("DISCOUNT-PRC", new BigDecimal("-45.6"));

                    baos.write(grp.getContents());
                }
                //In einem Byte-Array von Gruppenelementen festlegen.
                rec.setField("PRODUCT-B", baos.toByteArray());

                //Byte-Array und Ausgabe in Datei.
                byte[] buf = rec.getContents();
                StringUtil.dump("DEBUG:", buf, "");
                fos.write(buf);
            }
            fos.flush();
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

Eingabe der Hauptbilddatei

Gruppenelemente und OCCURS können nicht verwendet werden. Verwenden Sie daher das in der obigen Dateiausgabe gezeigte Bild.

Eingabe der Hauptbilddatei


    /**
     *Eingabe der Hauptbilddatei. <BR>
     *Geben Sie die Mainframe-Datei gemäß der Datensatzformatdefinition der RFML-Datei ein.<BR>
     * 1.Da sich das Gruppenelement und OCCURS nicht wie beabsichtigt verhalten, wird dieser Teil als Byte-Array betrachtet.<BR>
     * 2.Definieren Sie den Gruppenelementteil in einer anderen Datensatzformatdefinition, legen Sie dort das Byte-Array des MF-Zeichencodes fest und machen Sie es zu einem Java-Objekt.<br>
     */
    @Test
    public void test03MfFileInput() {
        //Erstellen Sie eine Mainframe-Datei.
        this.test02MfFileOutput();

        //Suchen und lesen Sie die Datensatzformatdefinition im Klassenpfad.
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument("jp.golden.cat.util.ORDER-FILE.rfml");
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }

        //Geben Sie eine Datei mit dem Zeichencode des Hauptrahmens ein.
        File ioFile = new File("./data/ORDER_FILE.dat");
        FileInputStream fis = null;
        try {
            Record rec = rfd.toRecordFormat("ORDER01-REC").getNewRecord();
            Record grp = rfd.toRecordFormat("PRODUCT-GR").getNewRecord();
            fis = new FileInputStream(ioFile);
            //Ruft die Anzahl der Bytes für einen Datensatz ab und erstellt ein Byte-Array für den Lesepuffer.
            byte[] recordBuf = new byte[rec.getRecordLength()];
            //Die MF-Datei enthält keine Zeilenvorschubzeichen. Daher wird es für die Anzahl der Bytes eines Datensatzes in den Puffer eingelesen.
            while (fis.read(recordBuf) != -1) {
                //Aufzeichnung aus dem Byte-Array des Puffers.
                rec.setContents(recordBuf);

                System.out.print("[" + rec.getField("REC-NO"));
                System.out.print("],[" + rec.getField("ORDER-NO"));

                //Der Code für den OCCURS-Teil des Gruppenelements.
                //Ein Bytestrom des gesamten Gruppenelements, von dem das Element erhalten wurde.
                ByteArrayInputStream bais = new ByteArrayInputStream((byte[]) rec.getField("PRODUCT-B"));
                //Erstellen Sie einen Lesepuffer für 1 OCCURS.
                byte[] groupBuf = new byte[grp.getRecordLength()];
                while (bais.read(groupBuf) != -1) {
                    grp.setContents(groupBuf);
                    System.out.print("],[" + grp.getField("PRODUCT-CD"));
                    System.out.print("],[" + grp.getField("PRODUCT-AMT"));
                    System.out.print("],[" + grp.getField("UNIT-PRC"));
                    System.out.print("],[" + grp.getField("DISCOUNT-PRC"));
                }
                System.out.println("]");
            }
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

19.04.2017 (Mi): Neue Erkenntnisse:

rfd.toRecord ("ORDER-REC"). getRecordLength () löst die folgende Ausnahme aus: 「com.ibm.as400.data.PcmlException: Value is not set. Processing element 'ORDER-REC.REC-NO'.」 Sie können die Länge wahrscheinlich nicht abrufen, da das Record-Objekt nicht im RecordFormatDocument-Objekt erstellt wurde. Ich ändere den Beispielcode, um ein Objekt mit getNewRecord () zu erstellen und dann die Länge zu erhalten.

19.04.2017 (Mi): Fehlerbehebung:

Sie haben den Puffer im RecordFormatDocument-Objekt nicht festgelegt, nachdem Sie ihn in den Puffer eingelesen haben. while (fis.read(buffer) != -1) { rfd.setValues("ORDER-REC", buffer);

2017/04/19 (Mi): Neu gefunden (getValue () -Methode wird ohne Erlaubnis zugeschnitten):

Der folgende Code ist beide Methoden, die ORDER-NOTE abrufen, jedoch mit unterschiedlichen Ergebnissen. (1) rfd.getValue("ORDER-REC.ORDER-NOTE") (2) rec.getField("ORDER-NOTE") In (1) wird der nachfolgende Leerzeichen von String ohne Erlaubnis gelöscht. (2) bleibt unverändert, wenn ein nachfolgender Raum vorhanden ist. (1) scheint PcmlDataValues.toObject () intern aufzurufen. Unter ihnen trimString.

PcmlDataValues.toObject()


//For Strings, trim blanks and nulls appropriately
if (dataType == PcmlData.CHAR) {
    newVal = trimString((String)newVal, getTrim());
}

getValue () macht etwas Egoistisches, daher ist es besser, die Methode getField () zu verwenden.

23.04.2017 (So): Neue Erkenntnisse:

AS400Array kann in RFML-Dateien schreiben, aber wenn es in RFML-Dateien eingelesen wird, wird seine OCCURS-Nummer nicht reproduziert. AS400Structre kann keine RFML-Dateien schreiben. Eine Ausnahme tritt auf, wenn ich versuche, sie als RFML-Datei zu lesen und zu verwenden.

26.04.2017 (Mi): Überprüfung der Eingabe / Ausgabe von Gruppenelementen:

Wenn Stream für die Dateieingabe / -ausgabe verwendet wird, ist es besser, das Byte-Array von Gruppenelementen mit Stream als Ganzes einzugeben / auszugeben.

Anderer vollständiger Code zur Bestätigung

IBMToolboxTest.java


package jp.golden.cat.util;

import static org.junit.Assert.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharConversionException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.ibm.as400.access.AS400Array;
import com.ibm.as400.access.AS400Bin4;
import com.ibm.as400.access.AS400ByteArray;
import com.ibm.as400.access.AS400DataType;
import com.ibm.as400.access.AS400PackedDecimal;
import com.ibm.as400.access.AS400Structure;
import com.ibm.as400.access.AS400Text;
import com.ibm.as400.access.ArrayFieldDescription;
import com.ibm.as400.access.BinaryFieldDescription;
import com.ibm.as400.access.CharacterFieldDescription;
import com.ibm.as400.access.HexFieldDescription;
import com.ibm.as400.access.PackedDecimalFieldDescription;
import com.ibm.as400.access.Record;
import com.ibm.as400.access.RecordFormat;
import com.ibm.as400.data.RecordFormatDocument;
import com.ibm.as400.data.XmlException;

/**
 *Testen der IBM Toolbox für Java.<BR>
 *
 * <H1>Installation und Einrichtung</H1><BR>
 *Auf der Download-Seite unten finden Sie die ZIP-Datei mit der OSS-Version des JAR(Zum Beispiel jtopen_9_3.zip)Herunterladen.<br>
 * 「jtopen_9_3.zip\lib\java8\jt400.Führen Sie "jar" durch den Klassenpfad.<br>
 * <br>
 * <H1>Informationsquellen usw.</H1> <BR>
 *IBM Toolbox für Java. Eine Übersichtsbeschreibung von IBM. URL:<a href=
 * "https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rzahh/page1.htm">https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rzahh/page1.htm</a><BR>
 *Programmieren von IBM Toolbox für Java. PDF Datei. Gliederung der Programmiermethoden. URL:<a href=
 * "https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rzahh/rzahhpdf.pdf">https://www.ibm.com/support/knowledgecenter/ja/ssw_ibm_i_73/rzahh/rzahhpdf.pdf</a><BR>
 * IBM Toolbox for Java API Document。URL:<a href=
 * "https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzahh/javadoc/index.html">https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_72/rzahh/javadoc/index.html</a><BR>
 * JTOpen: The Open Source version of the IBM Toolbox for
 *Java. Eine Übersicht über die Open Source Version. URL:<a href=
 * "http://jt400.sourceforge.net/">http://jt400.sourceforge.net/</a><BR>
 * JTOpen: The Open Source version of the IBM Toolbox for
 *Java-Download-Seite. URL:<a href=
 * "https://sourceforge.net/projects/jt400/">https://sourceforge.net/projects/jt400/</a><BR>
 *Download-URL für die neueste Version. URL:<a href=
 * "https://sourceforge.net/projects/jt400/files/latest/download?source=files">https://sourceforge.net/projects/jt400/files/latest/download?source=files</a><BR>
 *Lizenz für JTOpen und IBM Toolbox für Java. Beide sind "IBM Public License Version"
 * 1.0」。URL:<a href=
 * "https://opensource.org/licenses/ibmpl.php">https://opensource.org/licenses/ibmpl.php</a><BR>
 */
public class IBMToolboxTest {
    @Rule
    public ExpectedException thrown = ExpectedException.none();

    /**
     *Ausgabe der Hauptbilddatei. <BR>
     *Gibt die Mainframe-Datei gemäß der Datensatzformatdefinition der RFML-Datei aus.<BR>
     * {@code
      rec.setField("PRODUCT-GR", null);}An dem Ort{@code
    com.ibm.as400.access.ExtendedIllegalArgumentException: name (PRODUCT-GR): Field was not found.
    }<BR>
     *Ich bekomme eine Ausnahme. In der folgenden API-Dokumentation wird angegeben, dass Structure nicht unterstützt wird. Array wird ebenfalls nicht unterstützt.<BR>
     * <a href=
     * "https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzahh/javadoc/com/ibm/as400/data/RecordFormatDocument.html">
     * https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzahh/javadoc/com/ibm/as400/data/RecordFormatDocument.html</a>
     */
    @Test
    public void test01MfFileOutput() {
        //Suchen und lesen Sie die Datensatzformatdefinition im Klassenpfad.
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument("jp.golden.cat.util.ORDER-FILE.rfml");
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }

        //Dateiausgabe mit Hauptrahmenzeichencode.
        File ioFile = new File("./data/ORDER_FILE.dat");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            Record rec = rfd.toRecordFormat("ORDER01-REC").getNewRecord();
            for (short i = 1; i < 11; i++) {
                rec.setField("REC-NO", new Short(i));
                rec.setField("ORDER-NO", "170423-123");
                rec.setField("ZIP-CD", "103-0028");
                rec.setField("ADRESS", "Yaesu, Chuo-ku, Tokio");
                //↓ Hier tritt eine Ausnahme auf, also kommentieren Sie aus.
                // rec.setField("PRODUCT-GR", null);
                //Byte-Array und Ausgabe in Datei.
                byte[] buf = rec.getContents();
                StringUtil.dump("DEBUG:", buf, "");
                fos.write(buf);
            }
            fos.flush();
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     *Ausgabe der Hauptbilddatei. <BR>
     *Gibt die Mainframe-Datei gemäß der Datensatzformatdefinition der RFML-Datei aus.<BR>
     * 1.Da sich das Gruppenelement und OCCURS nicht wie beabsichtigt verhalten, wird dieser Teil als Byte-Array betrachtet.<BR>
     * 2.Definieren Sie den Gruppenelementteil in einer anderen Datensatzformatdefinition und legen Sie dort ein Java-Objekt fest, um ein Byte-Array mit MF-Zeichencode zu erstellen.<br>
     *3. 3. Über 2 über 1.Einstellen.
     */
    @Test
    public void test02MfFileOutput() {
        //Suchen und lesen Sie die Datensatzformatdefinition im Klassenpfad.
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument("jp.golden.cat.util.ORDER-FILE.rfml");
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }

        //Dateiausgabe mit Hauptrahmenzeichencode.
        File ioFile = new File("./data/ORDER_FILE.dat");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            Record rec = rfd.toRecordFormat("ORDER01-REC").getNewRecord();
            Record grp = rfd.toRecordFormat("PRODUCT-GR").getNewRecord();
            for (int i = 1; i < 11; i++) {
                rec.setField("REC-NO", new Short((short) i));
                rec.setField("ORDER-NO", "170423-123");
                rec.setField("ZIP-CD", "103-0028");
                rec.setField("ADRESS", "Yaesu, Chuo-ku, Tokio");

                //Der Code für den OCCURS-Teil des Gruppenelements.
                //Ein Bytestrom des gesamten Gruppenelements, an das das Element übertragen wird.
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                //Bytelänge des Ziels für die Elementübertragung ÷ 1 Bytelänge für OCCURS(PRODUCT-GR)= Anzahl der OCCC-URS
                int occursCount = rec.getFieldAsBytes("PRODUCT-B").length / grp.getRecordLength();
                //OCCURS Wiederholen Sie dies einige Minuten lang
                for (int j = 0; j < occursCount; j++) {
                    grp.setField("PRODUCT-CD", "ABCDEFGHIJ-000" + j);
                    grp.setField("PRODUCT-AMT", new BigDecimal("123.45"));
                    grp.setField("UNIT-PRC", new BigDecimal("+12345.67"));
                    grp.setField("DISCOUNT-PRC", new BigDecimal("-45.6"));

                    baos.write(grp.getContents());
                }
                //In einem Byte-Array von Gruppenelementen festlegen.
                rec.setField("PRODUCT-B", baos.toByteArray());

                //Byte-Array und Ausgabe in Datei.
                byte[] buf = rec.getContents();
                StringUtil.dump("DEBUG:", buf, "");
                fos.write(buf);
            }
            fos.flush();
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     *Eingabe der Hauptbilddatei. <BR>
     *Geben Sie die Mainframe-Datei gemäß der Datensatzformatdefinition der RFML-Datei ein.<BR>
     * 1.Da sich das Gruppenelement und OCCURS nicht wie beabsichtigt verhalten, wird dieser Teil als Byte-Array betrachtet.<BR>
     * 2.Definieren Sie den Gruppenelementteil in einer anderen Datensatzformatdefinition, legen Sie dort das Byte-Array des MF-Zeichencodes fest und machen Sie es zu einem Java-Objekt.<br>
     */
    @Test
    public void test03MfFileInput() {
        //Erstellen Sie eine Mainframe-Datei.
        this.test02MfFileOutput();

        //Suchen und lesen Sie die Datensatzformatdefinition im Klassenpfad.
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument("jp.golden.cat.util.ORDER-FILE.rfml");
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }

        //Geben Sie eine Datei mit dem Zeichencode des Hauptrahmens ein.
        File ioFile = new File("./data/ORDER_FILE.dat");
        FileInputStream fis = null;
        try {
            Record rec = rfd.toRecordFormat("ORDER01-REC").getNewRecord();
            Record grp = rfd.toRecordFormat("PRODUCT-GR").getNewRecord();
            fis = new FileInputStream(ioFile);
            //Ruft die Anzahl der Bytes für einen Datensatz ab und erstellt ein Byte-Array für den Lesepuffer.
            byte[] recordBuf = new byte[rec.getRecordLength()];
            //Die MF-Datei enthält keine Zeilenvorschubzeichen. Daher wird es für die Anzahl der Bytes eines Datensatzes in den Puffer eingelesen.
            while (fis.read(recordBuf) != -1) {
                //Aufzeichnung aus dem Byte-Array des Puffers.
                rec.setContents(recordBuf);

                System.out.print("[" + rec.getField("REC-NO"));
                System.out.print("],[" + rec.getField("ORDER-NO"));

                //Der Code für den OCCURS-Teil des Gruppenelements.
                //Ein Bytestrom des gesamten Gruppenelements, von dem das Element erhalten wurde.
                ByteArrayInputStream bais = new ByteArrayInputStream((byte[]) rec.getField("PRODUCT-B"));
                //Erstellen Sie einen Lesepuffer für 1 OCCURS.
                byte[] groupBuf = new byte[grp.getRecordLength()];
                while (bais.read(groupBuf) != -1) {
                    grp.setContents(groupBuf);
                    System.out.print("],[" + grp.getField("PRODUCT-CD"));
                    System.out.print("],[" + grp.getField("PRODUCT-AMT"));
                    System.out.print("],[" + grp.getField("UNIT-PRC"));
                    System.out.print("],[" + grp.getField("DISCOUNT-PRC"));
                }
                System.out.println("]");
            }
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * COMP-Java-Objekt von 4(Integer)Test zum Konvertieren.
     */
    @Test
    public void test01() {
        //Eingegebener Wert(MF-Byte-Daten)
        //Sie müssen sich keine Gedanken über die Bytereihenfolge machen, da die Ender sowohl von IBM Mainframe als auch von Java große Ender sind.
        byte[] mfData = new byte[] { 0x0A, 0x0B, 0x0C, 0x0D };
        StringUtil.dump("test01:input   :", mfData, "");

        // COMP-Java-Objekt von 4(Integer)Konvertieren zu.
        AS400Bin4 comp4 = new AS400Bin4();
        int actual = ((Integer) comp4.toObject(mfData, 0)).intValue();
        System.out.println("test01:actual  :" + actual);

        //Erwartete Wertschöpfung.
        int expected = 168496141;
        System.out.println("test01:expected:" + expected);

        //0x0A0B0C0D ist die Dezimalzahl 164896141.
        assertEquals(expected, actual);
    }

    /**
     *Java-Objekt(Integer)Von COMP-Test um auf 4 zu konvertieren.
     */
    @Test
    public void test02() {
        //Eingegebener Wert(Java-Objekt)
        Integer javaObject = new Integer(168496141);
        System.out.println("test02:input   :" + javaObject);

        //Java-Objekt(Integer)Von COMP-In 4 konvertieren.
        AS400Bin4 comp4 = new AS400Bin4();
        byte[] actual = comp4.toBytes(javaObject);
        StringUtil.dump("test02:actual  :", actual, "");

        //Erwartete Wertschöpfung.
        byte[] expected = new byte[] { 0x0A, 0x0B, 0x0C, 0x0D };
        StringUtil.dump("test02:expected:", expected, "");

        // test
        assertArrayEquals(expected, actual);
    }

    /**
     *PBC X-Format EBC DIC nach MS932(SJIS)Test zum Konvertieren. <BR>
     *
     * IBM Globalization - Coded character set identifiers.UR:<a href=
     * "https://www-01.ibm.com/software/globalization/ccsid/ccsid_registered.html">https://www-01.ibm.com/software/globalization/ccsid/ccsid_registered.html</a><br>
     *
     * IBM Globalization - Coded character set identifiers - CCSID
     * 5035。URL:<a href=
     * "https://www-01.ibm.com/software/globalization/ccsid/ccsid5035.html">https://www-01.ibm.com/software/globalization/ccsid/ccsid5035.html</a><br>
     *
     *Alternative Unicode-Konvertierungstabelle für CCSID 5035.URL:<a href=
     * "https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_9.5.0/com.ibm.db2.luw.admin.nls.doc/doc/c0022611.html">https://www.ibm.com/support/knowledgecenter/ja/SSEPGG_9.5.0/com.ibm.db2.luw.admin.nls.doc/doc/c0022611.html</a><br>
     *
     * 79.CCSID 5035 zur Eingabe von Kleinbuchstaben.URL:<a href=
     * "http://www.as400-net.com/tips/environment/79.html">http://www.as400-net.com/tips/environment/79.html</a><br>
     *
     * CCSID=930 「4370 UDC
     *Ein super Set von 5026 japanischen Katakana Kanji mit Charakteren. Kana-Priorität halber Breite(Kleinbuchstaben halber Breite können nicht gemischt werden)。<BR>
     * CCSID=939 「4370 UDC
     *Japanische lateinische Zeichen einschließlich Zeichen Kanji, 5035 Super-Set. Priorität der unteren Buchstaben mit halber Breite(Kana-Zeichen mit halber Breite können nicht gemischt werden)。<BR>
     */
    @Test
    public void test03() {
        //MF-Zeichencode, CCSID=930 「4370 UDC
        //Ein super Set von 5026 japanischen Katakana Kanji mit Charakteren. Kana-Priorität halber Breite(Kleinbuchstaben halber Breite können nicht gemischt werden)Byte-Array.
        // "123AαB"=0xF1F2F3C10E41410FC281。
        //Halbe Breite Katakana"EIN"Ist CCSID=930 ist 0x81. Dies ist CCSID=Es ist 939 0x56.
        //Zeichen in voller Breite"α"Ist der MF-Zeichencode 0X4141. Verschieben Sie dies heraus(0x0E)Und wechseln Sie hinein(0x0F)Deck, 0x0E41410F.
        byte[] mfData = new byte[] { (byte) 0xF1, (byte) 0xF2, (byte) 0xF3, (byte) 0xC1, 0x0E, 0x41, 0x41, 0x0F,
                (byte) 0xC2, (byte) 0x81 };
        StringUtil.dump("test03:input   :", mfData, "");
        System.out.println("test03:Anzahl der Eingabebytes:" + mfData.length);

        // CCSID=930 「4370 UDC
        //Ein super Set von 5026 japanischen Katakana Kanji mit Charakteren. Kana-Priorität halber Breite(Kleinbuchstaben halber Breite können nicht gemischt werden)Byte-Array
        //In Unicode konvertieren.
        int ccsid = 930;
        AS400Text xtype = new AS400Text(mfData.length, ccsid);
        String unicodeString = (String) xtype.toObject(mfData);
        System.out.println("test03:unicodeString Anzahl der Bytes:" + unicodeString.length());
        StringUtil.dump("test03:unicodeString:", unicodeString.getBytes(), "");

        //Unicode zu MS932(SJIS)Konvertieren zu.
        String encoding = "MS932";
        String actual = this.convertString(unicodeString, encoding);
        System.out.println("test03:actual  :" + actual);
        //Verschieben(0x0E)Und wechseln Sie hinein(0x0F)Da es keine gibt, sind es 2 Bytes weniger.
        System.out.println("test03:tatsächliche Anzahl von Bytes:" + this.getStringByteLength(actual, encoding));
        StringUtil.dump("test03:actual  :", this.getStringBytes(actual, encoding), "");

        //Machen Sie den erwarteten Wert.
        String expected = this.convertString("123AαB", encoding);
        System.out.println("test03:expected:" + expected);
        //Verschieben(0x0E)Und wechseln Sie hinein(0x0F)Da es keine gibt, sind es 2 Bytes weniger.
        System.out.println("test03:erwartete Anzahl von Bytes:" + this.getStringByteLength(expected, encoding));
        StringUtil.dump("test03:expected:", this.getStringBytes(expected, encoding), "");

        // test
        assertEquals(expected, actual);
    }

    /**
     *Zeichencode-Konvertierung.
     *
     * @param from Die Quellzeichenfolge.
     * @Parametercodierung Zeichencode nach der Konvertierung.
     * @return Die konvertierte Zeichenfolge.
     */
    String convertString(String from, String encoding) {
        String res = null;
        try {
            res = new String(getStringBytes(from, encoding), encoding);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return res;
    }

    /**
     *Konvertiert den Zeichencode und gibt ihn als Byte-Array zurück.
     *
     * @param from Die Quellzeichenfolge.
     * @Parametercodierung Zeichencode nach der Konvertierung.
     * @Byte-Array nach der Konvertierung zurückgeben.
     */
    byte[] getStringBytes(String from, String encoding) {
        byte[] res = null;
        try {
            res = from.getBytes(encoding);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return res;
    }

    /**
     *Gibt die Anzahl der Bytes nach der Zeichencodekonvertierung zurück.
     *
     * @param from Die Quellzeichenfolge.
     * @Parametercodierung Zeichencode nach der Konvertierung.
     * @return Die Anzahl der Bytes nach der Zeichencodekonvertierung.
     */
    int getStringByteLength(String from, String encoding) {
        return getStringBytes(from, encoding).length;
    }

    /**
     *Komplexer Datentypkonvertierungstest.
     */
    @Test
    public void test04() {
        //Java-Verbundobjekt
        Object[] javaObjects = {
                new Integer(88),
                new byte[] { 0x41 },
                new BigDecimal("-12.34"),
                "ABCDE"
        };

        //MF zusammengesetzte Datendefinition
        AS400DataType[] mfDataType = {
                new AS400Bin4(),
                new AS400ByteArray(4),
                new AS400PackedDecimal(4, 2),
                new AS400Text(10)
        };

        //Erzeugt einen Konverter mit der durch das Argument angegebenen zusammengesetzten MF-Datendefinition.
        AS400Structure converter = new AS400Structure(mfDataType);

        //Erzeugt ein Byte-Array mit MF-Zeichencode-Konvertierung aus einem zusammengesetzten Java-Objekt.
        byte[] outAS400 = converter.toBytes(javaObjects);
        StringUtil.dump("test04:", outAS400, "");

        Object[] outJavaObjects = (Object[]) converter.toObject(outAS400, 0);
        System.out.println("[" + outJavaObjects[0] + "]");
        StringUtil.dump("[", (byte[]) outJavaObjects[1], "]");    //Wenn 0x41 auf der Empfangsseite für 4 Bytes eingestellt ist, wird es linksbündig gesetzt. Füllen Sie den Rest mit 0x00.
        System.out.println("[" + outJavaObjects[2] + "]");
        System.out.println("[" + outJavaObjects[3] + "]");  //Wenn Sie auf der Empfangsseite 5 ABCDE-Zeichen für 10 Byte festlegen, wird dies mit der linken Klaue festgelegt. Der Rest ist Raum.

        // test
        assertEquals(88, outJavaObjects[0]);
        assertArrayEquals(new byte[] { 0x41, 0x00, 0x00, 0x00 }, (byte[]) outJavaObjects[1]);
        assertEquals(new BigDecimal("-12.34"), outJavaObjects[2]);
        assertEquals("ABCDE     ", outJavaObjects[3]);
    }

    /**
     *Ein Test, der ein Definitionsobjekt für das MF-Datensatzformat erstellt und dessen Werte entsprechend festlegt.
     */
    @Test
    public void test05() {
        //Artikeldefinition
        BinaryFieldDescription bfd = new BinaryFieldDescription(new AS400Bin4(), "REC-NO");
        CharacterFieldDescription cfd1 = new CharacterFieldDescription(new AS400Text(10), "ORDER-NO");
        CharacterFieldDescription cfd2 = new CharacterFieldDescription(new AS400Text(20), "ORDER-NOTE");

        //Datensatzformatdefinition
        RecordFormat rf = new RecordFormat();
        rf.addFieldDescription(bfd);
        rf.addFieldDescription(cfd1);
        rf.addFieldDescription(cfd2);

        //Generieren Sie einen Datensatz und legen Sie den Wert des Java-Objekts fest.
        Record rec = rf.getNewRecord();
        rec.setField("REC-NO", new Integer(1));
        rec.setField("ORDER-NO", "170415-123");
        rec.setField("ORDER-NOTE", "HELLO WORLD");

        //Holen Sie sich MF-Byte-Array.
        byte[] actual = null;
        try {
            actual = rec.getContents();
        } catch (CharConversionException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        //Erwarteter Wert.
        byte[] expected = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0xF1, (byte) 0xF7,
                (byte) 0xF0, (byte) 0xF4, (byte) 0xF1, (byte) 0xF5, (byte) 0x60, (byte) 0xF1, (byte) 0xF2, (byte) 0xF3,
                (byte) 0xC8, (byte) 0xC5, (byte) 0xD3, (byte) 0xD3, (byte) 0xD6, (byte) 0x40, (byte) 0xE6, (byte) 0xD6,
                (byte) 0xD9, (byte) 0xD3, (byte) 0xC4, (byte) 0x40, (byte) 0x40, (byte) 0x40, (byte) 0x40, (byte) 0x40,
                (byte) 0x40, (byte) 0x40, (byte) 0x40, (byte) 0x40 };
        StringUtil.dump("test05:actual  :", actual, "");
        StringUtil.dump("test05:expected:", expected, "");

        // test
        assertArrayEquals(expected, actual);
    }

    /**
     *Generieren Sie das Definitionsobjekt für das MF-Datensatzformat und den Eingabe- / Ausgabetest der EBCIDIC-Binärdatei entsprechend.
     */
    @Test
    public void test06() {
        RecordFormat rf = this.createOrderRecordFormat();
        Record rec = rf.getNewRecord();

        File ioFile = new File("./data/AS400.dat");

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            //10 Datensatzgenerierung
            for (int i = 1; i < 11; i++) {
                rec.setField("REC-NO", new Integer(i));
                rec.setField("AMOUNT", new BigDecimal("-12.34"));
                rec.setField("ORDER-NO", "170415-123");
                rec.setField("ORDER-NOTE", "HELLOαWORLD");
                //OutputStream kann als Argument von getContents angegeben werden.
                //Idiomly os.write(rec.getContents())Ich benutze es oft, also werde ich damit weitermachen.
                fos.write(rec.getContents());
            }
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (CharConversionException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(ioFile);
            rec = rf.getNewRecord();
            //Ermitteln Sie die Anzahl der Bytes für einen Datensatz und generieren Sie ein Byte-Array.
            int len = rec.getRecordLength();
            byte[] buffer = new byte[len];

            //Die MF-Datei enthält keine Zeilenvorschubzeichen. Daher wird die Anzahl der Bytes eines Datensatzes in den Puffer eingelesen.
            while (fis.read(buffer) != -1) {
                rec.setContents(buffer);
                StringUtil.dump("test06:", buffer, "");
                System.out.print(rec.getField("REC-NO"));
                System.out.print("," + rec.getField("ORDER-NO"));
                System.out.print("," + rec.getField("AMOUNT"));
                System.out.println("," + rec.getField("ORDER-NOTE"));
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     *Generieren Sie ein Definitionsobjekt für das MF-Datensatzformat aus der Definitionsdatei für das MF-Datensatzformat und testen Sie die Ausgabe der EBCDIC-Binärdatei entsprechend..
     *
     * @löst eine XmlException Record-Formatausnahme aus
     * @löst eine IOException File IO Exception aus
     */
    @Test
    public void test07() throws XmlException, IOException {
        //Generieren Sie die Definition des MF-Datensatzformats.
        RecordFormat rf = this.createOrderRecordFormat();

        //Speichern Sie die Definition des MF-Datensatzformats im Klassenpfad.
        this.saveRecordFormat(rf, new File("src/test/java/jp/golden/cat/util/ORDER.rfml"));

        //Suchen und lesen Sie die Definition des MF-Datensatzformats im Klassenpfad.
        RecordFormatDocument rfd = this.loadRecordFormatDocument("jp.golden.cat.util.ORDER.rfml");

        //Schreiben Sie in EBCDIC.
        File ioFile = new File("./data/AS400_2.dat");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            //10 Datensatzgenerierung
            for (int i = 1; i < 11; i++) {
                //Ich habe die Angewohnheit, Gegenstände anzugeben. "Name der Datensatzformatdefinition.Geben Sie den Artikel unter "Artikelname" an.
                rfd.setValue("ORDER-REC.REC-NO", new Integer(i));
                rfd.setValue("ORDER-REC.AMOUNT", new BigDecimal("-12.34"));
                rfd.setValue("ORDER-REC.ORDER-NO", "170415-123");
                rfd.setValue("ORDER-REC.ORDER-NOTE", "HELLOαWORLD");
                fos.write(rfd.toByteArray("ORDER-REC"));
            }
            fos.flush();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     *Generieren Sie ein Definitionsobjekt für das MF-Datensatzformat aus der Definitionsdatei für das MF-Datensatzformat und testen Sie die Eingabe der EBCDIC-Binärdatei entsprechend..
     *
     * @löst eine XmlException Record-Formatausnahme aus
     * @löst eine IOException File IO Exception aus
     */
    @Test
    public void test08() throws XmlException, IOException {
        //Suchen und lesen Sie die Definition des MF-Datensatzformats im Klassenpfad.
        RecordFormatDocument rfd = this.loadRecordFormatDocument("jp.golden.cat.util.ORDER.rfml");

        //Lesen Sie die EBCDIC-Datei.
        File ioFile = new File("./data/AS400_2.dat");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(ioFile);

            // rfd.toRecord("ORDER-REC").getRecordLength()Löst die folgende Ausnahme aus.
            // com.ibm.as400.data.PcmlException: Value is not set. Processing
            // <data> element 'ORDER-REC.REC-NO'.
            //Wahrscheinlich kann die Länge nicht abgerufen werden, da das Record-Objekt nicht im RecordFormatDocument-Objekt erstellt wurde.
            //Daher getNewRecord()Erstellen Sie ein Objekt mit und erhalten Sie dann die Länge.
            // int len = rfd.toRecord("ORDER-REC").getRecordLength();

            //Ermitteln Sie die Anzahl der Bytes für einen Datensatz und generieren Sie ein Byte-Array.
            int len = rfd.toRecordFormat("ORDER-REC").getNewRecord().getRecordLength();
            byte[] buffer = new byte[len];

            //Die MF-Datei enthält keine Zeilenvorschubzeichen. Daher wird die Anzahl der Bytes eines Datensatzes in den Puffer eingelesen.
            while (fis.read(buffer) != -1) {
                rfd.setValues("ORDER-REC", buffer);

                StringUtil.dump("test08:", rfd.toByteArray("ORDER-REC"), "");

                System.out.print("[" + rfd.getValue("ORDER-REC.REC-NO"));
                System.out.print("],[" + rfd.getValue("ORDER-REC.ORDER-NO"));
                System.out.print("],[" + rfd.getValue("ORDER-REC.AMOUNT"));
                System.out.print("],[" + rfd.getValue("ORDER-REC.ORDER-NOTE"));
                System.out.println("]");

                Record rec = rfd.toRecord("ORDER-REC");
                System.out.print("[" + rec.getField("REC-NO"));
                System.out.print("],[" + rec.getField("ORDER-NO"));
                System.out.print("],[" + rec.getField("AMOUNT"));

                //Der folgende Code ist beide ORDER-Dies ist eine Methode zum Abrufen von HINWEIS, das Ergebnis ist jedoch unterschiedlich.
                // (1) rfd.getValue("ORDER-REC.ORDER-NOTE")
                // (2) rec.getField("ORDER-NOTE")
                // (1)Der nachfolgende Leerzeichen des Strings wird ohne Erlaubnis gelöscht.(2)Bleibt intakt, wenn ein Leerzeichen vorhanden ist.
                // (1)Intern PcmlDataValues.toObject()Scheint anzurufen. Unter ihnen trimString.
                /*
                 * //For Strings, trim blanks and nulls appropriately if
                 * (dataType == PcmlData.CHAR) { newVal = trimString((String)
                 * newVal, getTrim()); }
                 */
                // getValue()Tut egoistische Dinge, also getField()Es ist besser, die Methode zu verwenden.
                System.out.print("],[" + rec.getField("ORDER-NOTE"));
                System.out.println("]");
            }
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     *Kann die Struktur OCCURS eine Datensatzformatdefinition sein? => Ich kann nicht.
     *
     * @löst eine XmlException Record-Formatausnahme aus
     * @löst eine IOException File IO Exception aus
     */
    @Test
    public void test09() throws XmlException, IOException {
        //AS400-Datentypdefinition
        AS400DataType[] as400Types = new AS400DataType[] {
                new AS400Text(10),
                new AS400PackedDecimal(4, 2),
        };
        AS400Structure as400Structure = new AS400Structure(as400Types);
        AS400Array as400Array = new AS400Array(as400Structure, 3);

        //Java-Objekt => AS400-Datenbyte-Array
        Object[] inJavaObject = new Object[as400Array.getNumberOfElements()];
        System.out.println("test09:AS400Array elements:" + as400Array.getNumberOfElements());
        for (int i = 0; i < inJavaObject.length; i++) {
            inJavaObject[i] = new Object[] {
                    new String("170415-123"),
                    new BigDecimal("-12.34"),
            };
        }
        byte[] as400bytes = as400Array.toBytes(inJavaObject);
        StringUtil.dump("test09:", as400bytes, "");

        //AS400-Datentyp(Structure+Array)Können Datensatzformatdefinitionen in XML gespeichert werden? => Ich kann nicht.
        ArrayFieldDescription afd = new ArrayFieldDescription(as400Array, "AMOUNTS");
        RecordFormat rf = new RecordFormat("TEST09-REC");
        rf.addFieldDescription(afd);
        File rfml = new File("src/test/java/jp/golden/cat/util/TEST09.rfml");
        FileOutputStream fos = null;
        try {
            //In RecordFormat kann AS400Structure mit der folgenden Ausnahme nicht als RFML-Datei gespeichert werden:
            // com.ibm.as400.data.XmlException: Data type AS400Structure is not
            // supported by RFML.
            //In der API-Dokumentation wurde auch angegeben, dass dies nicht unterstützt wurde. Ich möchte auch das mehrdimensionale AS400Array sehen.
            // https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_71/rzahh/javadoc/com/ibm/as400/data/RecordFormatDocument.html
            thrown.expect(com.ibm.as400.data.XmlException.class);
            thrown.expectMessage("Data type AS400Structure is not supported by RFML.");
            RecordFormatDocument rfd = new RecordFormatDocument(rf);
            fos = new FileOutputStream(rfml);
            rfd.toXml(fos);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }

    /**
     * AS400Array+AS400Structure kann nicht in eine RFML-Datei umgewandelt werden. Behalten Sie es also bei, bis die Anzahl der Bytes gezählt ist, und speichern Sie es in der RFML-Datei.
     *
     */
    @Test
    public void test10() {
        //AS400-Datentypdefinition
        AS400DataType[] types = new AS400DataType[] {
                new AS400Text(10),
                new AS400PackedDecimal(4, 2),
        };
        AS400Structure a400Structure = new AS400Structure(types);
        AS400Array as400Array = new AS400Array(a400Structure, 3);
        System.out.println("test10:AS400Structure byte length:" + a400Structure.getByteLength());
        System.out.println("test10:AS400Arrat byte length:" + as400Array.getByteLength());
        // AS400Array+Erstellen Sie eine Definition von AS400ByteArray für die Anzahl der Bytes von AS400Structure.
        AS400ByteArray as400ByteArray = new AS400ByteArray(as400Array.getByteLength());

        //Erstellen Sie eine Datensatzformatdefinition.
        BinaryFieldDescription bfd = new BinaryFieldDescription(new AS400Bin4(), "REC-NO");
        CharacterFieldDescription cfd1 = new CharacterFieldDescription(new AS400Text(10), "ORDER-NO");
        HexFieldDescription hfd = new HexFieldDescription(as400ByteArray, "AMOUNTS");   // AS400Array+AS400ByteArray für die Anzahl der Bytes von AS400Structure
        CharacterFieldDescription cfd2 = new CharacterFieldDescription(new AS400Text(20), "ORDER-NOTE");
        RecordFormat rf = new RecordFormat("ORDER3-REC");
        rf.addFieldDescription(bfd);
        rf.addFieldDescription(cfd1);
        rf.addFieldDescription(hfd);
        rf.addFieldDescription(cfd2);

        //In RFML-Datei speichern.
        File rfml = new File("src/test/java/jp/golden/cat/util/ORDER3.rfml");
        this.saveRecordFormat(rf, rfml);
    }

    /**
     * AS400Array+Da AS400Structure nicht in eine RFML-Datei umgewandelt werden kann, wird der Datensatz als RFML-Datei ausgegeben, die diesen Teil in einem Byte-Array ausdrückt..
     *
     * @löst eine XmlException Record-Formatausnahme aus
     * @löst eine IOException File IO Exception aus
     */
    @Test
    public void test11() throws XmlException, IOException {
        //AS400-Datentypdefinition
        AS400DataType[] types = new AS400DataType[] {
                new AS400Text(10),
                new AS400PackedDecimal(4, 2),
        };
        AS400Structure as400structure = new AS400Structure(types);
        AS400Array as400array = new AS400Array(as400structure, 3);

        //Generieren Sie ein Datensatzobjekt aus einer RFML-Datei.
        RecordFormatDocument rfd = this.loadRecordFormatDocument("jp.golden.cat.util.ORDER3.rfml");
        Record rec = rfd.toRecordFormat("ORDER3-REC").getNewRecord();

        //MF-Dateiausgabe
        File ioFile = new File("./data/AS4003.dat");
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(ioFile);
            //10 Datensatzgenerierung
            for (int i = 1; i < 11; i++) {
                rec.setField("REC-NO", new Integer(i));
                rec.setField("ORDER-NO", "170415-123");

                // AS400Array+Erstellen Sie ein Byte-Array für den AS400-Strukturteil
                //Erstellen Sie zunächst ein Java-Objekt, das festgelegt werden soll
                Object[] inJavaObject = new Object[as400array.getNumberOfElements()];
                for (int j = 0; j < inJavaObject.length; j++) {
                    inJavaObject[j] = new Object[] {
                            new String("170415-AA" + j),
                            new BigDecimal("-12.34"),
                    };
                }
                //Bild des Erstellens eines Byte-Arrays aus einem zweidimensionalen Java-Objekt
                byte[] as400bytes = as400array.toBytes(inJavaObject);
                System.out.println("test11:" + as400bytes.length);
                //Legen Sie das Byte-Array fest
                rec.setField("AMOUNTS", as400bytes);

                rec.setField("ORDER-NOTE", "HELLOαWORLD");
                fos.write(rec.getContents());
            }
            fos.flush();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * AS400Array+AS400Structure kann nicht in eine RFML-Datei konvertiert werden. Betrachten Sie AS400Structure daher als einen Datensatz, konvertieren Sie ihn in eine RFML-Datei und lesen Sie ihn.
     *
     * @löst eine XmlException Record-Formatausnahme aus
     * @löst eine IOException File IO Exception aus
     */
    @Test
    public void test12() throws IOException, XmlException {
        //Generieren Sie ein Datensatzobjekt aus einer RFML-Datei.
        RecordFormatDocument rfd = this.loadRecordFormatDocument("jp.golden.cat.util.ORDER4.rfml");
        Record rec1 = rfd.toRecordFormat("ORDER4-REC").getNewRecord();
        //Datensatzdefinition für 1 OCCURS. Ich möchte wirklich AS400 Structure verwenden, aber es wird nicht unterstützt.
        Record rec2 = rfd.toRecordFormat("AMOUNTS").getNewRecord();

        //MF-Dateieingabe
        File ioFile = new File("./data/AS4003.dat");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(ioFile);
            //Ermitteln Sie die Anzahl der Bytes für einen Datensatz und generieren Sie ein Byte-Array.
            int len = rec1.getRecordLength();
            byte[] buffer = new byte[len];
            //Die MF-Datei enthält keine Zeilenvorschubzeichen. Daher wird die Anzahl der Bytes eines Datensatzes in den Puffer eingelesen.
            while (fis.read(buffer) != -1) {
                rec1.setContents(buffer);

                System.out.print("[" + rec1.getField("REC-NO"));
                System.out.print("],[" + rec1.getField("ORDER-NO"));

                //Holen Sie sich das Byte-Array für die gesamten OCCURS
                byte[] amounts = (byte[]) rec1.getField("AMOUNTS");
                //Bytelänge des gesamten OCCURS ÷ 1 Bytelänge für OCCURS = Anzahl der OCCCURS
                int occursCount = amounts.length / rec2.getRecordLength();
                //OCCURS Wiederholen Sie dies einige Minuten lang
                for (int i = 0; i < occursCount; i++) {
                    //Crop 1 OCCURS aus dem Mengenbyte-Array.
                    rec2.setContents(amounts, i * rec2.getRecordLength());
                    //1 BESTELLUNG, aus der OCCURS besteht-Standardausgabe von CNO und AMOUNT
                    System.out.print("],[" + rec2.getField("ORDER-CNO"));
                    System.out.print("],[" + rec2.getField("AMOUNT"));
                }
                System.out.print("],[" + rec1.getField("ORDER-NOTE"));
                System.out.println("]");
            }
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     *Verhaltenstest von AS400Array.
     *
     *Die Aufteilung von AS400Array umfasst insgesamt 30 Byte Datenstruktur vom Typ X, 10 Byte x 3 OCCURS.
     *Speichern Sie dies in einer RFML-Datei. In XML zählen="3"Wird voraussichtlich mit ausgegeben. Bisher hat es funktioniert.
     *Wenn ich jedoch die RFML-Datei lese, ein Record-Objekt erstelle und die Länge erhalte, beträgt sie 10 Byte. OCCURS wird nicht reproduziert.
     *
     *Fazit:Es ist möglich, count in die RFML-Datei zu schreiben, verwenden Sie jedoch nicht count in der RFML-Datei, da diese beim Lesen verloren geht.
     *
     * @löst eine XmlException Record-Formatausnahme aus
     * @löst eine IOException File IO Exception aus
     */
    @Test
    public void test13() throws IOException, XmlException {
        //Artikeldefinition
        AS400Array as400Array = new AS400Array(new AS400Text(10), 3);
        ArrayFieldDescription afd = new ArrayFieldDescription(as400Array, "ORDER-NOTE");

        //Speichern Sie die Datensatzformatdefinition als Datei.
        RecordFormat rf = new RecordFormat("TEST13-REC");
        rf.addFieldDescription(afd);
        //Erwarteter Wert:10*3=30byte.
        int expected = rf.getNewRecord().getRecordLength();
        // count="3"Es wird in gespeichert.
        this.saveRecordFormat(rf, new File("src/test/java/jp/golden/cat/util/TEST13.rfml"));

        //Generieren Sie ein Datensatzobjekt aus einer RFML-Datei.
        RecordFormatDocument rfd = this.loadRecordFormatDocument("jp.golden.cat.util.TEST13.rfml");
        // 10*3=Ich erwarte 30 Bytes, aber aus irgendeinem Grund werden 10 zurückgegeben. count wird ignoriert.
        int actual = rfd.toRecordFormat("TEST13-REC").getNewRecord().getRecordLength();
        //Wenn ich versuche, es wie später zu speichern, verschwindet die Zählung und es wird gespeichert.
        this.saveRecordFormat(rfd.toRecordFormat("TEST13-REC"),
                new File("src/test/java/jp/golden/cat/util/TEST13_after.rfml"));

        System.out.println("test13:actual:" + actual);
        System.out.println("test13:expected:" + expected);
        // assertEquals(expected, actual);
        assertEquals(10, actual);

    }

    /**
     *Erstellen Sie eine Definition des Auftragsdatensatzformats.
     *
     * @return Definition des Auftragsdatensatzformats erstellen.
     */
    RecordFormat createOrderRecordFormat() {
        //Artikeldefinition
        BinaryFieldDescription bfd = new BinaryFieldDescription(new AS400Bin4(), "REC-NO");
        CharacterFieldDescription cfd1 = new CharacterFieldDescription(new AS400Text(10), "ORDER-NO");
        PackedDecimalFieldDescription pfd = new PackedDecimalFieldDescription(new AS400PackedDecimal(4, 2), "AMOUNT");
        CharacterFieldDescription cfd2 = new CharacterFieldDescription(new AS400Text(20), "ORDER-NOTE");

        //Datensatzformatdefinition
        RecordFormat rf = new RecordFormat("ORDER-REC");
        rf.addFieldDescription(bfd);
        rf.addFieldDescription(cfd1);
        rf.addFieldDescription(pfd);
        rf.addFieldDescription(cfd2);

        return rf;
    }

    /**
     *Ruft die Definition des MF-Datensatzformats aus dem Klassenpfad ab.
     *
     * @param rfmlClassPath。
     * @Rückgabe der MF-Datensatzformatdefinition.
     */
    RecordFormatDocument loadRecordFormatDocument(String rfmlClassPath) {
        RecordFormatDocument rfd = null;
        try {
            rfd = new RecordFormatDocument(rfmlClassPath);
        } catch (XmlException e) {
            throw new RuntimeException(e);
        }
        return rfd;
    }

    /**
     *Speichern Sie die Definition des MF-Datensatzformats als Datei.
     *
     * @param rf MF-Datensatzdefinitionsformat.
     * @param rfml
     *Dateipfad für die Definition des MF-Datensatzformats. Beachten Sie, dass die Definitionsdatei später nicht gelesen werden kann, wenn der Klassenpfad keine Definitionsdatei enthält.
     */
    void saveRecordFormat(RecordFormat rf, File rfml) {
        FileOutputStream fos = null;
        try {
            RecordFormatDocument rfd = new RecordFormatDocument(rf);
            fos = new FileOutputStream(rfml);
            rfd.toXml(fos);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (XmlException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     *Endian Bestätigung.
     *
     *Native Bytereihenfolge:LITTLE_ENDIAN<br>
     *Ursprünglicher Wert:0A0B0C0D12345678<br>
     * LITTLE_ENDIAN:0D0C0B0A BIG_ENDIAN:0A0B0C0D<br>
     * LITTLE_ENDIAN:78563412 BIG_ENDIAN:12345678<br>
     */
    @Test
    public void testEndian() {
        System.out.println("testEndian:");
        //Standardausgabe der nativen Bytereihenfolge.
        //In der internen Verarbeitung von Java ist es ein Big Endian, aber da die Intel-CPU ein kleiner Engel ist, wenn Sie die folgende Methode auf der Java-VM der Intel-CPU ausführen,
        //"Native Bytereihenfolge:LITTLE_"ENDIAN" wird angezeigt.
        System.out.println("Native Bytereihenfolge:" + ByteOrder.nativeOrder());

        byte[] mfData = new byte[] { 0xA, 0xB, 0xC, 0xD, 0x12, 0x34, 0x56, 0x78 };
        StringUtil.dump("Ursprünglicher Wert:", mfData, "");

        ByteArrayInputStream bis = null;
        try {
            bis = new ByteArrayInputStream(mfData);

            byte[] buffer = new byte[4];
            int len = -1;
            while ((len = bis.read(buffer)) != -1) {
                if (len != buffer.length) {
                    throw new IOException("Überprüfen Sie die Beziehung zwischen der Länge des Lesepuffers und dem Eingabewert.");
                }
                //Mit wenig Tolandian konvertiert.
                ByteBuffer byteBuff = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);
                int i = byteBuff.getInt();
                System.out.print(ByteOrder.LITTLE_ENDIAN);
                System.out.print(":" + StringUtil.toHexString(BigInteger.valueOf(i).toByteArray()));
                System.out.print("\t");

                //Mit Big Endian konvertiert.
                byteBuff = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN);
                i = byteBuff.getInt();
                System.out.print(ByteOrder.BIG_ENDIAN);
                System.out.print(":" + StringUtil.toHexString(BigInteger.valueOf(i).toByteArray()));
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    ;
                }
            }
        }
    }
}

Recommended Posts

Wie kann ich IBM Mainframe-Dateien in Java eingeben / ausgeben?
[Java] Wie man Dateien ausgibt und schreibt!
So zerlegen Sie eine Java-Klassendatei
Wie man JAVA in 7 Tagen lernt
Protokollausgabe in Datei in Java
So dekompilieren Sie eine Java-Klassendatei
Wie verwende ich Klassen in Java?
So benennen Sie Variablen in Java
So verketten Sie Zeichenfolgen mit Java
So implementieren Sie die Datumsberechnung in Java
So implementieren Sie den Kalman-Filter mit Java
Mehrsprachige Unterstützung für Java Verwendung des Gebietsschemas
So führen Sie eine Basiskonvertierung in Java durch
So geben Sie eine Java-Zeichenfolge auf dem Konsolenbildschirm aus
Konvertieren Sie SVG-Dateien in Java in PNG-Dateien
So erzwingen Sie Codierungskonventionen in Java
Einbetten von Janus Graph in Java
So erhalten Sie das Datum mit Java
Farbcodierung der Konsolenausgabe in Eclipse
So zeigen Sie eine Webseite in Java an
So erhalten Sie eine Klasse von Element in Java
So aktualisieren Sie eine vorgefertigte Datei in einem Docker-Container
So verbergen Sie Nullfelder als Antwort in Java
Ich habe versucht, neunundneunzig in Java auszugeben
So lösen Sie Ausdrucksprobleme in Java
Wie schreibe ich Java String # getBytes in Kotlin?
Aufrufen von Funktionen in großen Mengen mit Java Reflection
[Ruby] Verwendung der Standardausgabe bei der bedingten Verzweigung
So erstellen Sie einen Daten-URI (base64) in Java
Android-Laden Sie Bilddateien in den Azure Blob-Speicher in Java hoch
So konvertieren Sie A in a und a in A mit logischem Produkt und Summe in Java
Umgang mit TSV-Dateien und CSV-Dateien in Ruby
So konvertieren Sie eine Datei in ein Byte-Array in Java
So verwalten Sie Java EE-Projekte in Eclipse
Syntaxen Markieren Sie eine Datei wie Dockerfile.production mit Pycharm
Zusammenfassung der Implementierung von Standardargumenten in Java
Wie man altes Java (8er) in macOS 10.15 Catalina einfügt
Hinweise zur Verwendung regulärer Ausdrücke in Java
Lesen Sie Binärdateien in Java 1
[Java] Verwendung von Map
So deinstallieren Sie Java 8 (Mac)
Java - So erstellen Sie JTable
Verwendung von Java Optional
So minimieren Sie Java-Images
Wie schreibe ich einen Java-Kommentar
Verwendung der Java-Klasse
Lesen Sie die Standardeingabe in Java
[Java] Verwendung von removeAll ()
[Java] So zeigen Sie Wingdings an
Verwendung von Java Map
So legen Sie Java-Konstanten fest
Lesen Sie Binärdateien in Java 2