簡體   English   中英

PrintWriter vs DataOutputStream,奇怪的行為

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM