Java 套接字输出流上的PrintWriter会导致数据损坏/丢失

Java 套接字输出流上的PrintWriter会导致数据损坏/丢失,java,character-encoding,io,network-programming,java-io,Java,Character Encoding,Io,Network Programming,Java Io,我正试图通过套接字和PrintWriter从默认字符编码为UTF-8的服务器向默认字符编码为windows-1252的客户端发送字符串 当我运行下面的客户机时,我没有得到我的原始值141,尽管我甚至尝试使用CharsetDecoder转换字符串 作为一个控制测试,我尝试在Eclipse中运行这两个类,并通过下面的对话强制这两个类都使用UTF-8作为默认编码系统——我观察到,当两个客户端都使用UTF-8时,输出在客户端被成功解释 更新:看起来我能够流式传输字节并恢复初始格式,但为了这样做,我必须知

我正试图通过套接字和PrintWriter从默认字符编码为UTF-8的服务器向默认字符编码为windows-1252的客户端发送字符串

当我运行下面的客户机时,我没有得到我的原始值141,尽管我甚至尝试使用CharsetDecoder转换字符串

作为一个控制测试,我尝试在Eclipse中运行这两个类,并通过下面的对话强制这两个类都使用UTF-8作为默认编码系统——我观察到,当两个客户端都使用UTF-8时,输出在客户端被成功解释

更新:看起来我能够流式传输字节并恢复初始格式,但为了这样做,我必须知道服务器上使用的编码。在这种情况下,难道没有什么有用的图书馆吗?我宁愿不被迫以字节数组的形式传输数据

服务器:

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

//Runs on a server with default character encoding of UTF-8
public class TestServer {

public static void main(String[] args) throws Exception {

    PrintWriter writer = null;
    ServerSocket serverSocket = null;
    try {

        int x = 141;
        String s = "#" + (char)x;

        serverSocket = new ServerSocket(5555);
        Socket clientSocket = serverSocket.accept();

        writer = new PrintWriter(
                        (new OutputStreamWriter(clientSocket.getOutputStream())), true);

        System.out.println((int)s.charAt(1));
        writer.write(s);
    } catch(Exception e) {

        e.printStackTrace();
    } finally {

        writer.close();
        serverSocket.close();
    }
}
}

客户:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

//Runs on a server with default character encoding of windows-1252
public class TestClient {

public static void main(String[] args) throws Exception {

    Socket s = new Socket("localhost", 5555);
    BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));

    String string = reader.readLine();
    System.out.println((int)string.charAt(1)); //prints 194 when it was 141 on the other end

    //Charset.defaultCharset returns windows-1252
    CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
    CharBuffer buffer = decoder.decode(ByteBuffer.wrap(string.getBytes()));
    String convertedString = buffer.toString();

    System.out.println((int)convertedString.charAt(1)); //still prints 194

    String convertedString2 = new String(string.getBytes(), "UTF-8");
    System.out.println((int)convertedString2.charAt(1)); //prints 65533 ??

    s.close();
}
}
我只需将
write()
a
byte[]
直接写入
OutputStream
,避开中间人,然后从返回的
byte[]
在客户端构造一个新字符串。PrintWriter文档说:

它不包含写入原始字节的方法,因为程序 应使用未编码的字节流

在新服务器代码中,您将拥有:

    bytep[] s = new String("#" + (char)x).getBytes();;
    Socket clientSocket = serverSocket.accept();
    OutputStream writer = clientSocket.getOutputStream();
    System.out.println((int)s.charAt(1));
    writer.write(s);
在客户端,您将创建ByteArrayInputStream并将字节转换为字符串:

byte[] return_data = null;
Socket s = new Socket("localhost", 5555);
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int byte_read = bis.read();
while(byte_read != -1)
{
    baos.write(byte_read);
    byte_read = bis.read();

}

return_data = baos.toByteArray();
bis.close();
baos.close();   

String s = new String(return_data);

我发现有OutputStreamWriter和InputStreamReader构造函数将字符集作为参数。这就是我采用的解决方案:

在发件人上:

out = new PrintWriter(
   new BufferedWriter(new OutputStreamWriter(
        socket.getOutputStream(), "UTF-8")), true);
在接收器上:

in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));

隐马尔可夫模型。。我认为这是一种选择,但我真的试图避免它。我还可以使用其他更高级别的OutputStream实现吗?我认为使用byte[]方法的代码实际上稍微少一些。请参阅我提供的代码示例。谢谢。我想这是可行的,但是您的解决方案没有提供一种在不知道服务器字符编码的情况下在客户端解码的方法。另外,我真的想要一个不需要读/写字节的解决方案。我知道你想在这里做什么。我会调查并报告的。谢谢你的帮助:)