IBM Support

IBM Java Toolbox for i 实现Java Unicode与IBM i EBCDIC编码转换(下)

Technical Blog Post


Abstract

IBM Java Toolbox for i 实现Java Unicode与IBM i EBCDIC编码转换(下)

Body

IBM Java Toolbox for i数据转换类

从面向对象的角度,IBM Java Toolbox for i提供了一个AS400DataType接口,用于描述IBM i数据类型与Java数据类型之间的具体转换逻辑与规则。从AS400DataType接口对应的实现类,可大致可分为:

  • 数值
  • 文本
  • 日期
  • 复合类型(数字与文本)

1对应的是与数字相关的AS400DataType实现类。

1.  AS400DataType相关的实现类

  • 数字类型
  • 类说明
  • AS400Bin2
  • Java Short对象与IBM i 有符号双字节短整数的转换。
  • AS400Bin4
  • Java Integer对象与IBM i 有符号四字节整数的转换。
  • AS400ByteArray
  • IBM i字节数组之间的转换。
  • AS400Float4
  • Java Float对象与IBM i 有符号四字节浮点数的转换。
  • AS400Float8
  • Java Double对象与IBM i 有符号八字节浮点数的转换。
  • AS400PackedDecimal
  • Java BigDecimal对象与IBM i压缩十进制(PACKED DECIMAL)数的转换。
  • AS400UnsignedBin2
  • Java Integer对象与IBM i 无符号双字节整数的转换。
  • AS400UnsignedBin4
  • Java Long 对象与IBM i 无符号四字节整数的转换。
  • AS400ZonedDecimal
  • Java BigDecimal对象与IBM i区位十进制(ZONED DECIMAL)数的转换。

对于IBM iRPG程序而言,PACKED DECIMALZONED DECIMAL是两种常见的数值类型,虽然两者功能一样,都可以存放数值型数据,但它们所占存储空间是不一样的。ZONED DECIMAL用一个字节存放一个数字,而PACKED DECIMAL用一个字节存放两个数字。因此,PACKED DECIMAL节约了存储空间。基于存储空间的考虑,IBM iRPG编译器将ZONED DECIMAL数据自动转换为PACKED DECIMAL类型。因此,推荐使用PACKED DECIMAL类型,可节省存储控件,提高编译效率。另外,PACKED DECIMAL的长度定义为奇数长度会更节省存储空间。

数值转换类

作为例子,清单1描述的是如何使用AS400Bin4转换类,将IBM i格式的数值转换成Java整形。这里需要强调的是,所有的IBM i的数据我们都用字节数组来表示。

清单1. IBM i数值类型转换Java int类型

byte[] data = new byte[100];

// Number Converter

AS400Bin4 bin4Converter = new AS400Bin4();

Integer intObject = (Integer) bin4Converter.toObject(data,0);

int i = intObject.intValue();

清单2可以看作是清单1的逆过程,描述的是Java整形转换成IBM i格式的数值。

清单 2. Java int类型转换IBM i数值类型

Integer intObject = new Integer(22);

// Number Converter

AS400Bin4 bin4Converter = new AS400Bin4();

byte[] data = bin4Converter.toBytes(intObject);

int length = bin4Converter.getByteLength();

文本转换类

说完了数值类型,现在来看一下文本类型。从AS400DataType接口对应的实现类的角度,AS400Text实现了IBM i格式与Java 字符串的类型转换。作为示例,清单3描述了字符串从EBCDICUnicode的转换。

清单 3. IBM i字符串转换成Java字符串

byte[] data = new byte[100];

// Text Converter

AS400Text textConverter = new AS400Text(textLength, ccsid, system);

String javaText = (String) textConverter.toObject(data);

这里,我们结合前面图2给出的示例,验证EBCDIC编码的正确性。前面提到,字符序列“我来自IBM 对应EBCDIC的编码为:

57 D1 50 B3 5C B4 C9 C2 D4

根据我们前面的介绍,CCSID935表示的是简体中文字符集,双字节,因此分视为两个字符表,低字节对应CCSID836的字符表,高字节对应CCSID837的字符表。

因此,我们构造两个字节数组data1data2,如清单4所示。指定对应的CCSID值分别为837,与836,即采用CCSID935的简体中文字符集。然后,我们使用AS400Text类将其转换成Unicode编码,并显示。最后的结果是:It should print true? true

清单 4. EBCDIC中文字符编码应用举例

//CCSID=837编码汉字部分

byte[] data1 = {(byte)0x57,(byte)0xD1,(byte)0x50,(byte)0xB3,(byte)0x5C,(byte)0x74};

//CCSID=836编码非汉字部分

byte[] data2 = {(byte)0xC9,(byte)0xC2,(byte)0xD4};

String ccsid1 = "837";

String ccsid2 = "836";

AS400Text textConverter1 = new AS400Text(6, ccsid1);

AS400Text textConverter2 = new AS400Text(3, ccsid2);

String str1 = (String) textConverter1.toObject(data1);

String str2 = (String) textConverter2.toObject(data2);

System.out.println("It should print true? " + "我来自IBM".equals(str1+str2));

作为另一个特殊的文本类型转换类,AS400BidiTransform描述了双向语言(如阿拉伯语)的IBM i文本格式与Java Unicode字符串的转换,如示例清单5所示。

清单 5. IBM i双向语言文本与Java Unicode字符串的转换

// Java data to IBM i layout:

AS400BidiTransform abt = new AS400BidiTransform(424);

String dst = abt.toAS400Layout("some bidi string");

// Specifying a new CCSID for an existing AS400BidiTransform object:

abt.setAS400Ccsid(62234);                    // 420 RTL //

String dst = abt.toAS400Layout("some bidi string");

// Specifying a non-default string type for a given CCSID:

abt.setAS400StringType(BidiStringType.ST4);  // Vis LTR //

String dst = abt.toAS400Layout("some bidi string");

// Specifying a non-default string type for Java data:

abt.setJavaStringType(BidiStringType.ST11);  // Imp Context LTR //

String dst = abt.toAS400Layout("some bidi string");

// How to transform IBM i data to Java layout:

abt.setJavaStringType(BidiStringType.ST6);   // Imp RTL //

String dst = abt.toJavaLayout("some bidi string");

日期转换类

说完了数值类型与文本类型,接下来说一下日期类型。从AS400DataType接口对应的实现类的角度,抽象类AS400AbstractTime实现了IBM i格式与Java 字符串的类型转换。按照日期,时间,时间戳等进一步细分,AS400AbstractTime又分为三个子类AS400DateAS400TimeAS400Timestamp

我们知道,在Java中,用于表示时间的类是Date,分别对应java.sql.java.utilAS400Date实现的是IBM i时间格式与java.sql.Date类型的转换。相应地,AS400TimeAS400Timestamp均按照类似的逻辑,与java.sqlTimeTimestamp分别映射。关于AS400DateAS400TimeAS400Timestamp的用法,分别如清单6,清单7,清单8所示:

清单 6. AS400Date的使用

import java.text.SimpleDateFormat;

// value to be generated by AS400Date

java.sql.Date date1; 

// Set the formatter's time zone to GMT.

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

formatter.setTimeZone(as400.getTimeZone()); 

...

System.out.println("Date value: " + formatter.format(date1));

清单 7. AS400Time的使用

import java.text.SimpleDateFormat;

// value to be generated by AS400Time

java.sql.Time time1;

// Set the formatter's time zone to the server timezone.

SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss"); formatter.setTimeZone(as400.getTimeZone());

...

System.out.println("Time value: " + formatter.format(time1));

清单 8. AS400Timestamp的使用

import java.text.SimpleDateFormat;

// value to be generated by AS400Timestamp

java.sql.Timestamp timestamp1; 

// Set the formatter's time zone to the servers time zone

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

formatter.setTimeZone(as400.getTimeZone());

 ...

System.out.println("Timestamp value: " + formatter.format(timestamp1));

数组及结构转换类

谈完了数值类型,文本字符类型(包括对双向语言的支持),时间类型,最后我们来看一下符合类型。从AS400DataType接口对应的实现类的角度,对于符合类型的转换类支持分为两种:

AS400Array – 便于Java程序员方便操作数组类型。

AS400Structure -便于Java程序员方便操作结构体类型。

AS400Array的概念比较好理解,作为示例,清单9描述了AS400Structure的用法。

清单 9. AS400Structure的使用

AS400DataType[] myStruct =

{

   new AS400Bin4(),

   new AS400ByteArray(4),

   new AS400Float8(),

   new AS400Text(40)

};

// Create a conversion object using the structure.

AS400Structure myConverter = new AS400Structure(myStruct);

// Create the Java object that holds the data to send to the server.

Object[] myData =

{

   new Integer(88), // the four-byte number

   new byte[0], // the pad (let the conversion object 0 pad)

   new Double(23.45), // the eight-byte floating point number

   "This is my structure" // the character string

};

// Convert from Java object to byte array.

byte[] myAS400Data = myConverter.toBytes(myData);

Object[] myRoundTripData = (Object[])myConverter.toObject(myAS400Data,0);

Double doubleObject = (Double) myRoundTripData[2];

double d = doubleObject.doubleValue();

至此,我们已介绍完如何实现基于数值、文本、日期、数组及结构类型的数据转换。

 

总结

总之,EBCDICIBM特有的一种字符编码。按照CCSID的不同,对应不同的字符编码表。对于从事IBM i平台相关工作的程序开发人员而言,推荐使用IBM Java Toolbox for i,不用考虑IBM iEBCDICJava Unicode之间的转换规则,因为IBM Java Toolbox for i已经内置转码引擎,并提供两种不同粒度的代码转换类。这样,程序开发人员就可以把更多的时间与精力投入到程序的业务逻辑,提高开发效率,节省了成本。

 

参考资源

参看文章“Toolbox for Java JTOpen” ,了解IBM Java Toolbox for i的概要信息。

 

作者:皮光明

[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB57","label":"Power"}}]

UID

ibm11145026