2011-02-25 71 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