Java InputStream读取语言环境依赖吗?

时间:2019-01-28 15:56:52

标签: java utf-8 inputstream

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

这里是伪代码

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字符(例如“私”或“の”)上。如果我对这些字符执行以上代码,则输出为

  

读取字符串为:ç§?ã?转换后的byte []的char []为:[,￧,   ᄃ,?, ̄,?,],转换后的int []为:[,-25,-89,63,-29,63,-82,]

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

  

将字符串读取为:私の,并且byte []的转换后的char []为:[,￧,ᄃ,   チ, ̄,チ,ᆴ],转换后的int []为:[,-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,为什么读取的字节会受到影响?该功能是否与“读取”语言环境相关?

1 个答案:

答案 0 :(得分:1)

您选择的构造函数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);