Linux上的Java字节到字符串编码问题
我正在实现一个软件,其工作原理如下: 我有一个Linux服务器,运行输出文本的vt100终端应用程序。 我的程序对服务器进行远程登录,并将文本的位读取/解析为相关数据。 相关数据被发送到由Web服务器运行的小型客户机,该服务器在HTML页面上输出数据 我的问题是像“åäö”这样的特殊字符被输出为问号(经典) 背景:Linux上的Java字节到字符串编码问题,java,linux,character-encoding,apache-commons,Java,Linux,Character Encoding,Apache Commons,我正在实现一个软件,其工作原理如下: 我有一个Linux服务器,运行输出文本的vt100终端应用程序。 我的程序对服务器进行远程登录,并将文本的位读取/解析为相关数据。 相关数据被发送到由Web服务器运行的小型客户机,该服务器在HTML页面上输出数据 我的问题是像“åäö”这样的特殊字符被输出为问号(经典) 背景: 我的程序使用Apache Commons TelnetClient读取字节流。字节流被转换成一个字符串,然后相关的位被子字符串化,并用分隔符重新组合。在此之后,新字符串被转换回字节数
我的程序使用Apache Commons TelnetClient读取字节流。字节流被转换成一个字符串,然后相关的位被子字符串化,并用分隔符重新组合。在此之后,新字符串被转换回字节数组,并使用套接字发送到Web服务器运行的客户端。该客户端从接收到的字节创建一个字符串,并在标准输出上打印出来,Web服务器从标准输出读取和输出HTML 步骤1: 字节[]-->字符串-->字节[]-->[发送到客户端] 步骤2: 字节[]-->字符串-->[打印输出] 问题:
当我在Windows上运行Java程序时,所有字符(包括“åäö”)都会正确输出到生成的HTML页面上。但是,如果我在Linux上运行该程序,所有特殊字符都将转换为“?”(问号) Web服务器和客户端当前正在Windows上运行(步骤2) 代码:
程序基本上是这样工作的: 我的节目:
byte[] data = telnetClient.readData() // Assume method works and returns a byte[] array of text.
// I have my reasons to append the characters one at a time using a StringBuffer.
StringBuffer buf = new StringBuffer();
for (byte b : data) {
buf.append((char) (b & 0xFF));
}
String text = buf.toString();
// ...
// Relevant bits are substring'ed and put back into the String.
// ...
ServerSocket serverSocket = new ServerSocket(...);
Socket socket = serverSocket.accept();
serverSocket.close();
socket.getOutputStream.write(text.getBytes());
socket.getOutputStream.flush();
Web服务器运行的客户端:
Socket socket = new Socket(...);
byte[] data = readData(socket); // Assume this reads the bytes correctly.
String output = new String(data);
System.out.println(output);
假设读写之间的同步工作正常
想法:我尝试了不同的编码和解码字节数组的方法,但没有结果。我对字符集编码问题有点陌生,希望得到一些建议。Windows“Windows 1252”中的默认字符集似乎允许特殊字符从服务器一直到Web服务器,但在Linux计算机上运行时,默认字符集是不同的。我尝试运行一个“Charset.defaultCharset().forName()”,它显示我的Linux计算机被设置为“US-ASCII”。我以为Linux默认为“UTF-8”
如何让程序在Linux上运行?通常,依赖平台默认编码是个坏主意,尤其是对于网络通信协议
newstring()
和String.getBytes()
都被重载,以允许您指定编码。因为您可以控制编码和解码,所以只需使用UTF-8(硬编码)
还要检查您的代码是否使用了
FileInputStream
、FileOutputStream
、InputStreamReader
和OutputStreamWriter
,所有这些都依赖于平台默认编码(前两个是专用的,这使得它们非常无用).依赖平台默认编码通常是个坏主意,尤其是对于网络通信协议
newstring()
和String.getBytes()
都被重载,以允许您指定编码。因为您可以控制编码和解码,所以只需使用UTF-8(硬编码)
还要检查您的代码是否使用了FileInputStream
、FileOutputStream
、InputStreamReader
和OutputStreamWriter
,所有这些都可能依赖于平台默认编码(前两个是专用的,这使得它们非常无用)。String(byte[]bytes,String编码)
是你的朋友。只需将所有原始字节读入字节缓冲区,并使用此构造函数将字节解码为Java字符串。(或:转码为UTF-16,内部字符编码)
方法getBytes(字符串编码)
将字符串编码为字节。String(byte[]字节,字符串编码)
是您的朋友。只需将所有原始字节读入字节缓冲区,并使用此构造函数将字节解码为Java字符串。(或:转码为UTF-16,内部字符编码)
方法
getBytes(字符串编码)
将字符串编码为字节。关键细节是从telnetClient.readData()返回的数据的编码是什么?听起来像是windows-1252
。考虑到这一点,你有两个选择。您可以将所有字符串
操作的编码显式设置为windows-1252
:
text.getBytes("windows-1252");
String output = new String(data, "windows-1252");
或者,您可以使用java.nio.charset.charset
将telnet数据转换为不太特定于平台的数据,如UTF-8
,如下示例:--仍然显式设置字符串
操作中的字符集。关键细节是从telnetClient.readData()
?听起来像是windows-1252
。考虑到这一点,你有两个选择。您可以将所有字符串
操作的编码显式设置为windows-1252
:
text.getBytes("windows-1252");
String output = new String(data, "windows-1252");
或者,您可以使用java.nio.charset.charset
将telnet数据转换为不太特定于平台的数据,如UTF-8
,如下示例:--仍然明确设置String
操作中的字符集。如何使用StringBuffer进行解码<代码>buf.append(新字符串(新字节[]{b},“UTF-8”))
?但是,否则我应该在整个程序(包括客户端)中始终使用UTF-8进行解码和编码?@snipes83:删除StringBuffer。这是一个毫无意义的、容易出错的复杂问题,并且需要更复杂的逻辑才能为UTF-8工作,因为它将对ASCII之外的字符使用多个字节。或者解释你想这样做的原因,我们可能会找到更好的解决方案来实现你真正想要的。否则,可以在任何地方使用UTF-8。避免在两者之间转换