Java Socket文件传输不完整问题求助:文件损坏或大小不符
问题分析与解决方案
核心问题
你的文件传输不稳定、文件损坏的原因有两个:
- 服务器无法判断传输结束:Socket输入流的
read()方法返回-1的前提是对方关闭了输出流或Socket连接。客户端仅调用flush()但未告知服务器传输结束,导致服务器的while循环会一直阻塞在read(),直到客户端Socket意外关闭,此时可能还有部分数据未被完整读取,造成文件截断。 - 服务器代码存在语法错误:
try-with-resources语句后缺少大括号,BufferedInputStream downloader未被纳入资源管理,可能导致资源泄漏或数据缓冲未及时写入文件。
修复方案
方案一:通过关闭输出流标记传输结束
这种方式简单直接,适合不需要复用Socket的场景:
修改客户端uploadFile方法:
在flush()后调用socket.shutdownOutput(),明确告知服务器没有更多数据传输:
public void uploadFile(Socket socket, String path) { try (BufferedInputStream file = new BufferedInputStream(new FileInputStream(path)); BufferedOutputStream uploader = new BufferedOutputStream(socket.getOutputStream())) { byte[] bytes = new byte[1024]; int count; while ((count = file.read(bytes)) != -1) uploader.write(bytes, 0, count); uploader.flush(); socket.shutdownOutput(); // 发送结束标记,服务器read()会返回-1 } catch (Exception e) { e.printStackTrace(); } }
修复服务器downloadFile方法的语法错误:
将BufferedInputStream纳入try-with-resources管理,确保资源正确释放:
public void downloadFile(Socket socket, String path) { try (BufferedOutputStream file = new BufferedOutputStream(new FileOutputStream(path)); BufferedInputStream downloader = new BufferedInputStream(socket.getInputStream())) { byte[] bytes = new byte[1024]; int count; while ((count = downloader.read(bytes)) != -1) file.write(bytes, 0, count); file.flush(); // 确保缓冲数据写入文件 } catch (IOException e) { System.out.println("Respounder.downloadFile("+path+"): IOException"); e.printStackTrace(); } }
方案二:先传输文件长度(更可靠,支持Socket复用)
如果需要后续复用Socket进行其他通信,建议先发送文件总长度,服务器根据长度精确读取数据,无需依赖流关闭:
客户端修改:
使用DataOutputStream先发送文件长度,再传输文件内容:
public void uploadFile(Socket socket, String path) { try (BufferedInputStream file = new BufferedInputStream(new FileInputStream(path)); DataOutputStream uploader = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()))) { File targetFile = new File(path); uploader.writeLong(targetFile.length()); // 先发送文件总字节数 byte[] bytes = new byte[1024]; int count; while ((count = file.read(bytes)) != -1) uploader.write(bytes, 0, count); uploader.flush(); } catch (Exception e) { e.printStackTrace(); } }
服务器修改:
使用DataInputStream先读取文件长度,再循环读取对应字节数:
public void downloadFile(Socket socket, String path) { try (BufferedOutputStream file = new BufferedOutputStream(new FileOutputStream(path)); DataInputStream downloader = new DataInputStream(new BufferedInputStream(socket.getInputStream()))) { long totalBytes = downloader.readLong(); // 获取文件总长度 byte[] bytes = new byte[1024]; long receivedBytes = 0; int count; // 精确读取到指定字节数后停止 while (receivedBytes < totalBytes && (count = downloader.read(bytes, 0, (int) Math.min(bytes.length, totalBytes - receivedBytes))) != -1) { file.write(bytes, 0, count); receivedBytes += count; } file.flush(); } catch (IOException e) { System.out.println("Respounder.downloadFile("+path+"): IOException"); e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者hansoko
相关产品推荐
相关产品推荐

