You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 20:27:04