【问题标题】:why does "STRING".getBytes() work different according to the Operation System为什么“STRING”.getBytes() 的工作方式因操作系统而异
【发布时间】:2021-10-01 22:36:00
【问题描述】:

我正在运行下面的代码,我得到的结果与“some_string”.getBytes() 不同,具体取决于我是在 Windows 还是 Unix 中。任何字符串都会出现这个问题(我尝试了一个非常简单的 ABC 和同样的问题。

查看控制台中打印的以下差异。

下面的代码使用 Java 7 进行了很好的测试。如果你完全复制它,它将运行。

此外,请查看下面两张图片中十六进制的差异。前两个图像显示了在 Windows 中创建的文件。您可以分别使用 ANSI 和 EBCDIC 查看十六进制值。第三张图片,黑色的,来自 Unix。您可以看到十六进制(-c 选项)和我认为它是 EBCDIC 的可读字符。

所以,我的直截了当的问题是:为什么这些代码的工作方式不同,因为我在这两种情况下都使用 Java 7?我应该检查某处的任何特定属性吗?也许,Windows 中的 Java 有某种默认格式,而 Unix 中它有另一种。如果是这样,我必须检查或设置哪个属性?

Unix 控制台:

$ ./java -cp /usr/test.jar test.mainframe.read.test.TestGetBytes
H = 76 - L
< wasn't found

Windows 控制台:

H = 60 - <
H1 = 69 - E
H2 = 79 - O
H3 = 77 - M
H4 = 62 - >
End of Message found

整个代码:

package test.mainframe.read.test;

import java.util.ArrayList;

public class TestGetBytes {

       public static void main(String[] args) {
              try {
                     ArrayList ipmMessage = new ArrayList();
                     ipmMessage.add(newLine());

                     //Windows Path
                     writeMessage("C:/temp/test_bytes.ipm", ipmMessage);
                     reformatFile("C:/temp/test_bytes.ipm");
                     //Unix Path
                     //writeMessage("/usr/temp/test_bytes.ipm", ipmMessage);
                     //reformatFile("/usr/temp/test_bytes.ipm");
              } catch (Exception e) {

                     System.out.println(e.getMessage());
              }
       }

       public static byte[] newLine() {
              return "<EOM>".getBytes();
       }

       public static void writeMessage(String fileName, ArrayList ipmMessage)
                     throws java.io.FileNotFoundException, java.io.IOException {

              java.io.DataOutputStream dos = new java.io.DataOutputStream(
                           new java.io.FileOutputStream(fileName, true));
              for (int i = 0; i < ipmMessage.size(); i++) {
                     try {
                           int[] intValues = (int[]) ipmMessage.get(i);
                           for (int j = 0; j < intValues.length; j++) {
                                  dos.write(intValues[j]);
                           }
                     } catch (ClassCastException e) {
                           byte[] byteValues = (byte[]) ipmMessage.get(i);
                           dos.write(byteValues);
                     }
              }
              dos.flush();
              dos.close();

       }

       // reformat to U1014
       public static void reformatFile(String filename)
                     throws java.io.FileNotFoundException, java.io.IOException {
              java.io.FileInputStream fis = new java.io.FileInputStream(filename);
              java.io.DataInputStream br = new java.io.DataInputStream(fis);

              int h = br.read();
              System.out.println("H = " + h + " - " + (char)h);

              if ((char) h == '<') {// Check for <EOM>

                     int h1 = br.read();
                     System.out.println("H1 = " + h1 + " - " + (char)h1);
                     int h2 = br.read();
                     System.out.println("H2 = " + h2 + " - " + (char)h2);
                     int h3 = br.read();
                     System.out.println("H3 = " + h3 + " - " + (char)h3);
                     int h4 = br.read();
                     System.out.println("H4 = " + h4 + " - " + (char)h4);
                     if ((char) h1 == 'E' && (char) h2 == 'O' && (char) h3 == 'M'
                                  && (char) h4 == '>') {
                           System.out.println("End of Message found");
                     }
                     else{
                           System.out.println("EOM not found but < was found");
                     }
              }
              else{
                     System.out.println("< wasn't found");
              }
       }
}

【问题讨论】:

    标签: java linux unix binary ebcdic


    【解决方案1】:

    调用getBytes() 时没有指定字符集,因此它使用底层平台的默认字符集(或Java 本身的默认字符集,如果在Java 启动时指定)。这在String documentation 中有说明:

    公共字节[] getBytes()

    将此字符串编码为字节序列使用平台的默认字符集,将结果存储到新的字节数组中。

    getBytes() 有一个重载版本,可让您在代码中指定字符集。

    公共字节[] getBytes(Charset charset)

    使用给定的字符集将此字符串编码为字节序列,并将结果存储到新的字节数组中。

    【讨论】:

    • 在 Windows 上,默认字符集很可能是 cp1252(或特定于国家/地区的字符集)。许多 Linux 使用 UTF08。在大型机上,我认为它会是 EBCDIC
    • 可能 cp1252 通常只在西方国家。世界各地使用了许多 Ansi 字符集,并为它们提供了许多 Windows 代码页。不要假设cp1252,根据你的实际需要明确。
    • 谢谢。这是我第一次使用大型机,老实说,我从来不需要在 Windows 世界中设置字符集。我在提出建议后解决了这个问题,这确实是我问题的答案。顺便说一句,如果你能在这个论坛上向我推荐一些文章或问题,以了解字符集的真正含义,我将不胜感激。在我工作的大型机中,字符集是 IBM1047(我在打印 java.nio.charset.Charset.defaultcharset 时得到了这个)。该问题已通过在 getBytes() 中传递 org.apache.commons.io.Charsets.UTF_8 得到解决。我发现奇怪的是我在 java.nio 中没有找到相同的常量。
    • @JimC:Java有一个java.nio.charset.StandardCharsets类,你可以使用StandardCharsets.UTF_8org.apache.commons.io.Charsets documentation 甚至声明:“已弃用。使用 Java 7 的 StandardCharsets”。
    猜你喜欢
    • 1970-01-01
    • 2011-09-07
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    相关资源
    最近更新 更多