2011-05-10 103 views
4

我正在爲學校作業創建文件服務器應用程序。我目前擁有的是一個簡單的Client類,它通過TCP發送一個圖像,一個Server類接收它並將其寫入文件。Java DataInputStream長度

這是我的客戶端代碼

import java.io.*; 
import java.net.*; 

class Client { 
    public static void main(String args[]) throws Exception { 
     long start = System.currentTimeMillis(); 
     Socket clientSocket = new Socket("127.0.0.1", 6789); 
     DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream()); 

     File file = new File("hot.jpg"); 
     FileInputStream fin = new FileInputStream(file); 
     byte sendData[] = new byte[(int)file.length()]; 
     fin.read(sendData); 

     outToServer.write(sendData, 0, sendData.length); 
     clientSocket.close(); 

     long end = System.currentTimeMillis(); 
     System.out.println("Took " + (end - start) + "ms"); 
    } 
} 

,這是我的服務器代碼。

import java.io.*; 
import java.net.*; 

class Server { 
    public static void main(String args[]) throws Exception { 
     ServerSocket serverSocket = new ServerSocket(6789); 
     Socket connectionSocket = serverSocket.accept(); 
     DataInputStream dis = new DataInputStream(connectionSocket.getInputStream()); 

     byte[] receivedData = new byte[61500]; // <- THIS NUMBER 

     for(int i = 0; i < receivedData.length; i++) 
      receivedData[i] = dis.readByte(); 

     connectionSocket.close(); 
     serverSocket.close(); 

     FileOutputStream fos = new FileOutputStream("received.jpg"); 
     fos.write(receivedData); 
     fos.close(); 
    } 
} 

我的問題是如何獲取正在發送的文件的大小。如果您檢查Server的代碼,您會看到我現在已經對數字進行了硬編碼,即61500。我如何動態檢索這個號碼?

或者,我這樣做是錯誤的方式?什麼是替代解決方案?

回答

6

在發送文件之前添加一個「長度字段」。 (注意,因爲你讀的文件到內存中的文件的最大尺寸可以〜2GB)


發送文件寫入文件的長度之前:

outToServer.writeInt(sendData.length); 

而且接收讀出的第一長度,並用它作爲一個長度時:

int dataLength = dis.readInt() 
    byte[] receivedData = new byte[dataLength]; 

更好的方法是而不是先將文件讀入內存,但直接從FileInputStream傳輸 - 那麼您可以傳輸更大的文件!

+0

感謝兄弟,做了這項工作。 – 2011-05-10 08:38:52

+0

發送之前,我沒有看到將文件讀入內存的位置?它在哪裏,我該如何避免它? – 2011-05-10 08:47:16

+0

@David Weng:在使用'< - THIS NUMBER'時,您將爲整個文件分配足夠的內存。你很少需要這樣做,並且它不會擴展到適度大的文件。 – EJP 2011-05-10 09:09:40

2

如果知道長度,使用readFully()比一次讀取一個字節效率更高。

在這種情況下,您不需要知道長度,您可以編寫循環來讀取/寫入儘可能多的數據。

InputStream is = connectionSocket.getInputStream(); 

byte[] bytes = new byte[8192]; 
int len; 
while((len = is.read(bytes)) > 0) 
    fos.write(bytes, 0, len); 

可避免當您閱讀它複製數據讀取整個文件到內存中。

FileInputStream fis = new FileInputStream(filename); 
OutputStream os = socket.getOutputStream(); 

byte[] bytes = new byte[8192]; 
int len; 
while((len = fis.read(bytes)) > 0) 
    os.write(bytes, 0, len); 

您可以使用Apache IOUtils .copy(),如果要執行從一個流複製到另一個。

此方法的優點是文件可以是任何大小(大於2 GB)。使用數組限制爲2 GB(並使用更多內存)

+0

你的第二個代碼示例沒有多大意義 – codymanix 2011-05-10 16:04:45

+0

@codymanix,它基本上是第一個示例的代碼副本。什麼是沒有意義的? – 2011-05-10 16:27:41