Java InputStream 读取语言环境依赖?

Java InputStream read locale dependent?

我有客户端-服务器应用程序。客户端(C++ 应用程序)正在发送 UTF8 编码的字符串,而服务器(Java 应用程序)正在通过套接字端口通信读取这些字符串。我在服务器端读取字符串时遇到问题,以防服务器托管在 Windows OS 上,区域设置为 CP-1252。

这是伪代码

private transient Socket socket = null;
private transient InputStream in = null;
private transient OutputStream out = null;

socket = new Socket(server, port);
out = socket.getOutputStream();
in = socket.getInputStream();

Socket 和 InputStream 在一些不同的函数中初始化,实际的字符串读取如下函数所示:

ReadString()
{
    byte[] backbytes = new byte[2048];

    {
        if ((c = in.read(backbytes)) > 0) {
            if (debug)
                logger.trace("Read " + c + " bytes");
            total = total + c;
            char[] convertedChar = new char[backbytes.length];
            int[] convertedInt = new int[backbytes.length];
            for(int i=0;i < backbytes.length;i++){
                convertedChar[i] = (char) backbytes[i];
                convertedInt[i] = (int) backbytes[i];
            }

            logFilePrint.print("Read string as : " + new String(backbytes, 0, c) + " and the converted char[] of byte[] is : ");
            printArray(logFilePrint, convertedChar);
            logFilePrint.print(" and converted int[] is : " );
            printArray(logFilePrint, convertedInt);
            logFilePrint.flush();

            sb.append(new String(backbytes, 0, c));
        } else {
          break;
        }
    }
}

某些 Unicode 字符(例如“私”或“の”)会出现此问题。如果我对这些字符执行上面的代码,我得到输出

Read string as : ç§?ã? and the converted char[] of byte[] is : [, ￧, ᄃ, ?,  ̄, ?,] and converted int[] is : [, -25, -89, 63, -29, 63, -82,]

但是,如果我通过使用“-Dfile.encoding=UTF-8”将 JVM 的字符集设置为 UTF8 来更改服务器编码,我得到的输出为:

Read string as : 私の and the converted char[] of byte[] is : [, ￧, ᄃ, チ,  ̄, チ, ᆴ] and converted int[] is : [, -25, -89, -127, -29, -127, -82,]

非 UTF8 模式下的问题似乎是针对字节为“0x81”的字符。敌人,例如字符'私'有UTF-8编码'0xE7 0xA7 0x81'和'の'有UTF-8编码'0xE3 0x81 0xAE'

据我了解,InputStream "in.read(backbytes)" 只是读取发送的数据字节。为什么在 JVM 字符集为 UTF-8 和非 UTF8 的情况下读取字节会受到影响?函数 'read' 语言环境依赖吗?

您选择的构造函数,String(byte[] encoded, int offset, int length),使用默认平台编码将字节转换为字符。它明确取决于它运行的环境。

对于可移植代码来说,这是一个糟糕的选择。对于网络应用程序,明确指定要使用的编码。您可以将其作为网络协议的一部分进行协商,或者指定一个有用的默认值,例如 UTF-8。

有多种 API 可以对文本进行编码和解码。例如,String 构造函数 String(byte[] encoded, int offset, int length, Charset encoding) 可以这样使用:

String str = new String(backbytes, 0, c, StandardCharsets.UTF_8);