[英]PrintWriter vs DataOutputStream, weird behavior
我正在创建一个服务器/客户端 model 以将图像文件从服务器发送到客户端。 只涉及一个套接字(所有数据都通过它发送)。
服务器首先发送图像文件的大小,然后通过 BufferedOutputStream 以字节为单位发送文件数据。 客户端首先接收到文件的大小(size),创建一个byte[size] imageBytes,然后通过一个BufferedInputStream将接收到的文件数据写入imageBytes。
似乎直截了当。 当我以不同的方式发送文件大小时,就会出现问题。
方式1:使用DataOutputStream和DataInputStream发送和接收文件大小为int。
方式2:使用PrintWriter打印ln(文件大小),然后刷新; 使用 BufferedReader 来 readLine()。
方式1工作正常。 但是方式 2 发送的图像文件不正确。
我想知道这是不是因为 BufferedReader 在读取后仍然保留它的缓冲区,并且缓冲区随后被 BuffereInputStream 读取。
以下是代码:
服务器:
package test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServer {
public static void main(String[] args){
try {
ServerSocket serverSocket = new ServerSocket(9090);
Socket ss = serverSocket.accept();
System.out.println("Client connected!");
File file = new File("ServerFiles/Songs/Covers/album1.jpg"); //Change this path to your own path
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] imageBytes = new byte[(int) file.length()];
bis.read(imageBytes);
bis.close();
//Way 1-------------------------------------------------------------
DataOutputStream dos = new DataOutputStream(ss.getOutputStream());
dos.writeInt((int) file.length());
System.out.println("dos wrote "+file.length());
//End Way 1---------------------------------------------------------
//Way 2-------------------------------------------------------------
// PrintWriter pw = new PrintWriter(ss.getOutputStream());
// pw.println(file.length());
// pw.flush();
// System.out.println("pw flushed!");
//End Way 2---------------------------------------------------------
BufferedOutputStream bos = new BufferedOutputStream(ss.getOutputStream());
bos.write(imageBytes);
bos.flush();
System.out.println("bos flushed!");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客户:
package test;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestClient extends JFrame{
Socket cs;
ImageIcon imageIcon;
public static void main(String[] args){
try {
Socket socket = new Socket(InetAddress.getLocalHost(), 9090);
new TestClient(socket);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public TestClient(Socket cs) throws IOException{
this.cs = cs;
init();
}
private void init() throws IOException{
imageIcon = getImageIcon();
JLabel jl = new JLabel(imageIcon);
JPanel content = (JPanel) this.getContentPane();
content.add(jl);
this.setSize(600,400);
this.setVisible(true);
}
private ImageIcon getImageIcon() throws IOException{
//Way 1-------------------------------------------------------------
DataInputStream dis = new DataInputStream(cs.getInputStream());
int size = dis.readInt();
System.out.println("size="+size);
//End Way 1---------------------------------------------------------
//Way 2-------------------------------------------------------------
// BufferedReader br = new BufferedReader(new InputStreamReader(cs.getInputStream()));
// int size = Integer.parseInt(br.readLine());
// System.out.println("size="+size); //Print size
//End Way 2---------------------------------------------------------
BufferedInputStream bis = new BufferedInputStream(cs.getInputStream());
System.out.println("bis.available()="+bis.available()); //Print bis.available()
byte[] imageBytes = new byte[size];
bis.read(imageBytes);
return new ImageIcon(imageBytes);
}
}
输出:
方式一:
服务器:
Client connected!
dos wrote 23215
bos flushed!
客户:
size=23215
bis.available()=23215
方式二:
服务器:
Client connected!
pw flushed!
bos flushed!
客户:
size=23215
bis.available()=6837
我想说差异来自DataOutputStream
以二进制格式写入 integer,即将 integer 拆分为 4 个字节并写入这些字节,而PrintWriter
执行String.valueOf(paramInt)
并因此发送字符串"23215"
的字节给客户。
既然您已经在发送二进制数据(图像),为什么不坚持方式 1? 您通常不需要 header 来供人类阅读。
没有关于输入流的合同说您将在一次读取中获得所有数据。 您需要继续循环 available() 直到它返回一个负数。 修改您的代码以执行此操作,然后再次比较您的两个方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.