Java Socket客户端服务器传输大文件时tar.gz压缩包损坏无法解压问题
问题诱因
- 单次读写逻辑缺陷:服务端和客户端的流读写都仅执行1次,
InputStream.read()方法只会读取最多缓冲区长度的字节数,当文件大小超过你设置的8000字节缓冲区时,剩余内容不会被读取和传输,客户端最终只拿到文件的前8000字节,自然无法正常解压读取。 - 流操作不规范:服务端写完数据后未调用
flush()刷出缓冲区残留数据,也未主动关闭socket输出流告知客户端传输结束,可能导致部分数据残留在系统缓冲区未发出。 - 无完整性校验逻辑:传输前后没有校验文件长度或内容哈希,无法感知文件是否传输完整。
修复方案
首先调整核心传输逻辑,用循环读写处理全量文件数据,同时增加文件长度校验:
修改后服务端transferData方法
private static void transferData(Socket ts) throws IOException { File zipFile = new File(zipName); FileInputStream fi = new FileInputStream(zipFile); OutputStream os = ts.getOutputStream(); // 先发送文件总长度,供客户端校验完整性 os.writeLong(zipFile.length()); byte[] buffer = new byte[8192]; int readLen; // 循环读取文件直到全部读完 while ((readLen = fi.read(buffer)) != -1) { os.write(buffer, 0, readLen); } os.flush(); fi.close(); // 主动关闭输出流,通知客户端数据发送完毕 ts.shutdownOutput(); }
修改后客户端fileCopy方法
public boolean fileCopy(String sensor_node_ip, String filename) throws InterruptedException{ Socket s = null; try { s = new Socket(sensor_node_ip, 7104); System.out.println("connection done"); InputStream iss = s.getInputStream(); // 读取服务端发送的文件总长度 long totalFileLen = iss.readLong(); FileOutputStream fr = new FileOutputStream(filename); byte[] buffer = new byte[8192]; int readLen; long receivedLen = 0; // 循环读取直到接收到全量文件数据 while (receivedLen < totalFileLen && (readLen = iss.read(buffer)) != -1) { fr.write(buffer, 0, readLen); receivedLen += readLen; } fr.flush(); fr.close(); s.close(); System.out.println("Tar file received from " + sensor_node_ip + ", received bytes: " + receivedLen); // 校验接收长度和总长度是否一致,返回传输结果 return receivedLen == totalFileLen; } catch (IOException e){ e.printStackTrace(); return false; } }
额外优化建议
- 可在传输完成后增加MD5值校验,进一步确保文件内容没有传输错误
- 给Socket设置连接超时和读取超时,避免网络异常时程序永久卡住
- 无需调用
Runtime.exec执行rm命令删除旧文件,直接用Java原生File.delete()方法操作即可,兼容性和安全性更高
内容的提问来源于stack exchange,提问作者se7en
相关产品推荐
相关产品推荐

