问题 在java中将EBCDIC转换为ASCII


所以我应该使用Java将EBCDIC文件转换为ASCII。到目前为止,我有这个代码:

public class Migration {
InputStreamReader reader;
StringBuilder builder;

public Migration(){
    try {
        reader = new InputStreamReader(new FileInputStream("C:\\TI3\\Legacy Systemen\\Week 3\\Oefening 3\\inputfile.dat"),
               java.nio.charset.Charset.forName("ibm500") );
    } catch(FileNotFoundException e){
        e.printStackTrace();
    }
    builder = new StringBuilder();
}

public void read() throws IOException {
    int theInt;
    while((theInt = reader.read()) != -1){
        char theChar = (char) theInt;
        builder.append(theChar);

    }

    reader.close();
}

@Override
public String toString(){
    return builder.toString();
    }
}

文件描述如下:

 02 KDGEX.
      05 B1-LENGTH PIC S9(04) USAGE IS COMP.
      05 B1-CODE PIC S9(04) USAGE IS COMP.
      05 B1-NUMBER PIC X(08).
      05 B1-PPR-NAME PIC X(06).
      05 B1-PPR-FED PIC 9(03).
      05 B1-PPR-RNR PIC S9(08) USAGE IS COMP.
      05 B1-DATA.
        10 B1-VBOND PIC 9(02).
        10 B1-KONST.
          20 B1-AFDEL PIC 9(03).
          20 B1-KASSIER PIC 9(03).
          20 B1-DATZIT-DM PIC 9(04).
        10 B1-BETWYZ PIC X(01).
        10 B1-RNR PIC X(13).
        10 B1-BETKOD PIC 9(02).
        10 B1-VOLGNR-INF PIC 9(02).
        10 B1-QUAL-PREST PIC 9(03).
        10 B1-REKNUM PIC 9(12).
        10 B1-REKNR REDEFINES B1-REKNUM.
          20 B1-REKNR-PART1 PIC 9(03).
          20 B1-REKNR-PART2 PIC 9(07).
          20 B1-REKNR-PART3 PIC 9(02).
        10 B1-VOLGNR-M30 PIC 9(03).
        10 B1-OMSCHR.
          15 B1-OMSCHR1 PIC X(14).
          15 B1-OMSCHR2 PIC X(14).
        10 B1-OMSCHR-INF REDEFINES B1-OMSCHR.
          15 B1-AANT-PREST PIC 9(02).
          15 B1-VERSTR PIC 9(01).
          15 B1-LASTDATE PIC 9(06).
          15 B1-HONOR PIC 9(06).
          15 B1-RIJKN PIC X(13).
        10 FILLER--1 PIC 9(02).
        10 B1-INFOREK PIC 9(01).
        10 B1-BEDRAG-EUR PIC 9(08).
        10 B1-BEDRAG-DV PIC X(01).
        10 B1-BEDRAG-RMG-DV REDEFINES B1-BEDRAG-DV PIC X(01).
      05 FILLER PIC X(5).

我们可以忽略每一行的前2个字节。问题是由于读者没有正确地转换它们,因此存在USAGE IS COMP的字节,我认为我应该将它们读作字节或其他东西,尽管我不知道如何。


8635
2017-12-03 11:09


起源

具有1-4位的COMP是双字节二进制。具有5-9位的COMP是四字节二进制。它来自IBM大型机(最有可能),因此如果重要的话,它将是Big Endian。 X'0010'的值为16,X'00000010'也是如此。所有其他数据都是纯无符号字符数据,因此如果更方便,可以将其视为大块字符。它 可能 是不需要前四个字节。可变长度记录前面有两个双字节二进制字段,包含长度和零。这可能是巧合。 - Bill Woodger
只是补充一点,无论谁给你那个档案,都会让你变得更加困难。如果 所有 您需要的字段是普通字符字段,EBCDIC到ASCII转换只能通过任何实用程序为您提供文件来完成 - 您没有要编写的程序,没有轮子可以重新发明。 - Bill Woodger
如果你不能在另一端得到改变,这是一个现有的轮子 stackoverflow.com/questions/17448008/... - Bill Woodger
谢谢你的所有回复,我会看看它 - Robin-Hoodie


答案:


如果我正确解释这种格式,你有一个带有固定长度记录的二进制文件格式。其中一些记录不是字符数据(COBOL计算字段?)

因此,您必须使用处理每个记录的各个字段的更低级别的方法来读取记录:

import java.io.*;

public class Record {
  private byte[] kdgex = new byte[2]; // COMP
  private byte[] b1code = new byte[2]; // COMP
  private byte[] b1number = new byte[8]; // DISPLAY
  // other fields

  public void read(DataInput data) throws IOException {
    data.readFully(kdgex);
    data.readFully(b1code);
    data.readFully(b1number);
    // other fields
  }

  public void write(DataOutput out) throws IOException {
    out.write(kdgex);
    out.write(b1code);
    out.write(b1number);
    // other fields
  }
}

在这里,我已经为记录的前三个字段使用了字节数组,但你可以在适当的地方使用其他更合适的类型(比如a short 对于第一个领域 readShort。) 注意:我对场宽的解释可能是错误的;这只是一个例子。

DataInputStream类 通常用作 数据输入 实现。

由于源代码和目标编码中的所有字符都使用每个代码点一个八位字节,因此您应该能够使用如下方法对字符数据字段进行代码转换:

public static byte[] transcodeField(byte[] source, Charset from, Charset to) {
  byte[] result = new String(source, from).getBytes(to);
  if (result.length != source.length) {
    throw new AssertionError(result.length + "!=" + source.length);
  }
  return result;
}

我建议用COBOL标记你的问题(假设这是这种格式的来源),以便其他人可以更加权威地对数据源的格式说话。


7
2017-12-03 12:13



正如Bill Woodger在他的评论中指出的那样...... IBM COBOL S9(04)COMP字段是一个双字节2的补码大端二进制数,符号位于最左边的位。 S9(08)COMP类似但占用4个字节。 - NealB
@NealB感谢您的纠正 - McDowell


我也遇到了将EBCDIC转换为ASCII字符串的问题。 请找到下面的代码将单个EBCDIC转换为ASCII字符串。

public class EbcdicConverter
{
    public static void main(String[] args) 
        throws Exception
    {
        String ebcdicString =<your EBCDIC string>;
        // convert String into InputStream
        InputStream is = new ByteArrayInputStream(ebcdicString.getBytes());
        ByteArrayOutputStream baos=new ByteArrayOutputStream();

        int line;
         while((line = is.read()) != -1) {
             baos.write((char)line);
         }
         String str = baos.toString("Cp500");
         System.out.println(str);
    }
}

2
2017-11-08 17:29



如何处理问题中的非字符字段?如果您没有非字符数据,只需在文件传输中执行,不要为其编写复杂的代码。 - Bill Woodger