Java InputStream读取区域设置相关



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

这是伪代码

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字符上,例如"私'或'の'.如果我为这些字符执行上面的代码,我会得到的输出

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

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

将字符串读取为:私の字节[]的转换后的char[]为:[,￧, ᄃ,チ,  ̄, チ, ᆴ]转换后的int[]为:[,-25,-89,-127,-29,-127和-82,]

非UTF8模式下的问题似乎是字节为"0x81"的字符。Foe,例如字符私'具有UTF-8编码"0xE7 0xA7 0x81"one_answers"の'具有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(byte[] encoded, int offset, int length, Charset encoding)可以这样使用:

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

最新更新