考虑这段代码:
public static void main(String[] args) {
transcode();
System.setProperty("ibm.swapLF", "true");
transcode();
}
private static void transcode() {
byte EBCDIC_NL = 0x15; //next line
byte EBCDIC_LF = 0x25; //line feed
byte EBCDIC_CR = 0x0D; //carriage return
ebcdicToUtf16(EBCDIC_NL);
ebcdicToUtf16(EBCDIC_LF);
ebcdicToUtf16(EBCDIC_CR);
utf16ToEbcdic("\u0085"); //next line
utf16ToEbcdic("\n"); //line feed
utf16ToEbcdic("\r"); //carriage return
}
private static void ebcdicToUtf16(byte... b) {
String utf16 = new String(b, Charset.forName("IBM500"));
System.out.format("%02x -> %04x%n", b[0] & 0xFF, utf16.charAt(0) & 0xFFFF);
}
private static void utf16ToEbcdic(String s) {
byte[] b = s.getBytes(Charset.forName("IBM500"));
System.out.format("%04x -> %02x%n", s.charAt(0) & 0xFFFF, b[0] & 0xFF);
}
当在 IBM JVM (1.7) 上运行时,将发出:
15 -> 000a
25 -> 000a
0d -> 000d
0085 -> 15
000a -> 15
000d -> 0d
15 -> 000a
25 -> 000a
0d -> 000d
0085 -> 15
000a -> 25
000d -> 0d
此 IBM JVM 补丁 SI23602 http://www-01.ibm.com/support/docview.wss?uid=nas36a46c090c815e0078625716c00528125解释:
其他背景:行业中有两个标准
换行函数的 EBCDIC 处理。这两个标准分别用于
LF (0x25) CDRA 或 NL (0x15) MVS 开放版。早期版本
Java(直到 JDK 1.3)在换行符的使用上不一致
使用 0x15 与大多数 EBCDIC 编码兼容,而其他一些编码
使用了0x25。从 JDK 1.4 开始,IBM JDK 选择
对使用 NL (0x15) 的所有 EBCDIC 字符编码进行标准化。
为了解决换行函数使用的双重标准,这
APAR 将提供一个开关,允许某些 EBCDIC 转换器
交换使用 0x15 或 0x25 作为换行函数。默认
所有 EBCDIC 字符编码的行为仍将映射
unicode \u000A 字符到 EBCDIC 0x15 字符。指定
java属性"ibm.swapLF=true"
会导致转换器切换
其 unicode \u000A 到 EBCDIC 0x25 的映射。转换器其中
支持此 java 属性作为开关的有:Cp284、Cp285、Cp500、
Cp1140、Cp1141、Cp1142、Cp1143、Cp1144、Cp1145、Cp1146、Cp1147、
Cp1148、Cp1149。
这两种设置都不会将任何内容映射到 U+0085(为 NL/NEL 指定 Unicode 值 http://www.unicode.org/Public/UNIDATA/UnicodeData.txt)。大概这是出于历史原因 - ASCII 没有 NEL 字符,并且 EBCDIC 到 ASCII 一定是相对常见的。
实现 Unicode 编码的无损往返是可能的,但不太可能常用编码器 http://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html会这样做。
Notes:
- Sun/Oracle JVM 不会遵守ibm.swapLF系统属性。
-
Unicode 换行函数指南 http://www.unicode.org/reports/tr13/不解释 NL 到 LF 映射,但提供其他信息