2011-02-25 35 views
4

當我使用套接字編程傳輸大文件時,接收到的文件不完整,即它是一個mp3文件,當我播放聲音時很奇怪。 的代碼是:帶插座的大文件傳輸

服務器端:

File myFile = new File("abc.mp3"); 
{ 
    Socket sock = servsock.accept(); 
    int packetsize=1024; 
    double nosofpackets=Math.ceil(((int) myFile.length())/packetsize); 
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(myFile)); 
    for(double i=0;i<nosofpackets+1;i++) { 
     byte[] mybytearray = new byte[packetsize]; 
     bis.read(mybytearray, 0, mybytearray.length); 
     System.out.println("Packet:"+(i+1)); 
     OutputStream os = sock.getOutputStream(); 
     os.write(mybytearray, 0,mybytearray.length); 
     os.flush(); 
    } 
} 

客戶端:

int packetsize=1024; 
FileOutputStream fos = new FileOutputStream("zz.mp3"); 
BufferedOutputStream bos = new BufferedOutputStream(fos); 
double nosofpackets=Math.ceil(((int) (new File("abc.mp3")).length())/packetsize); 
for(double i=0;i<nosofpackets+1;i++) 
{ 
    InputStream is = sock.getInputStream(); 
    byte[] mybytearray = new byte[packetsize]; 
    int bytesRead = is.read(mybytearray, 0,mybytearray.length); 
    System.out.println("Packet:"+(i+1)); 
    bos.write(mybytearray, 0,mybytearray.length); 
} 
sock.close(); 
bos.close(); 

在我使用​​只是簡單的客戶端(我可以把長度來自服務器端的文件)。

如果客戶端和服務器是同一臺機器,則該代碼可以很好地工作,但如果文件位於不同的計算機上,則該文件會變形。

+0

如果您有緩衝輸出流,爲什麼要手動緩衝?你爲什麼不把所有東西都讀完,一次寫完呢? – corsiKa 2011-02-25 05:31:53

+0

是不是有限制的緩衝區的大小。因此,我把文件分成n塊發送它們。 – anonymous123 2011-02-25 05:34:57

+0

@anonymous當然有一個限制,但你不必寫所有的分塊傳輸。它會自動發生。 – EJP 2013-08-01 05:33:21

回答

17

的規範方式在Java中複製數據流:

int count; 
byte[] buffer = new byte[8192]; 
while ((count = in.read(buffer)) > 0) 
{ 
    out.write(buffer, 0, count); 
} 

適用於任何緩衝區大小大於零。應該儘量避免將緩衝區大小與輸入大小聯繫起來的誘惑。

8

我認爲問題在於你忽略了各種read調用返回的值,並假設它們完全填充緩衝區。這是有問題的:

  • 從文件讀取時,最後讀可能不會填充緩衝區。

  • 從套接字讀取時,任何讀取可能會在填充緩衝區之前返回。

最終結果是您的寫入將垃圾放入流(在服務器端)和目標文件(在客戶端)。

此外,根據文件的大小將文件分割成塊是毫無意義的。只要閱讀,直到你到達文件的末尾。

0

不要使用數據包。
嘗試使用ByteArrayOutputStream而不是使用靜態字節數組。
保持從輸入流讀取,直到你達到EOF。 n將這些寫入ByteArrayOutputStream。


InputStream is = sock.getInputStream(); 
ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
int byteToBeRead = -1; 
while((byteToBeRead = is.read())!=-1){ 
baos.write(byteToBeRead); 
} 
byte[] mybytearray = baos.toByteArray(); 
bos.write(mybytearray, 0,mybytearray.length); 

希望這會有所幫助。

+1

爲什麼?任意文件根本不適合內存。最好假設他們不會,並據此進行。您的解決方案沒有任何建議:冗餘初始化;增加延遲;無限的內存成本;而且它比我發佈的替代品更多的代碼,沒有這些問題。 – EJP 2011-02-27 02:00:35

+0

@EJP hw是否修復了緩衝區的大小? – Sujay 2011-02-28 08:28:25

+0

@Sujay:這並不重要。 8192是一個方便的號碼,不是太大,不能太小。我發佈的循環將適用於任何大於0的緩衝區大小。 – EJP 2011-02-28 08:54:06

4

不要重新發明輪子,使用IOUtils.copy()

+1

+1,告訴不要重新發明輪子 – 2013-11-22 15:09:39