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

Java中使用ByteBuffer复制文件时目标文件体积偏大问题

问题原因分析与解决办法

嘿,我一眼就瞅出你这个文件复制程序的问题啦!

为什么目标文件会变大?

你的核心问题出在写入文件时没有只写实际读取到的有效字节。看你的代码,每个复制方法里都是这么写的:

fout.write(buffersm); // 或者buffermd、bufferlg、bufferxl

当你用fin.read(buffer)读取数据时,返回的i是这次实际读到的字节数——只有前i个字节是源文件的有效数据。但如果直接调用write(buffer),会把整个缓冲区的内容都写入文件,包括缓冲区里之前读取残留的旧数据!

举个例子:假设最后一次读取时,源文件只剩500字节,但你的缓冲区是1MB,这时候i=500,但你写入了整个1MB,就多写了1024*1024 - 500个无效字节,累积起来目标文件自然就比源文件大了。

解决办法

把所有fout.write(buffer)的调用改成只写入实际读取到的i个字节,也就是用write的重载方法:

fout.write(buffer, 0, i);

比如修改你的copysm方法:

private static void copysm(File a, File b) {
    try {
        length = a.length();
        fin = new FileInputStream(a);
        fout = new FileOutputStream(b);
        i = fin.read(buffersm);
        j = 0;
        while (i != -1) {
            j += i;
            fout.write(buffersm, 0, i); // 这里改成写入i个字节
            System.out.print("Copying... " + decimal_p_.format(((j / length) * 100)) + " " + a.getName() + " to " + b.getPath() + " buffer: " + buffersm.length + " \r");
            i = fin.read(buffersm);
        }
    } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
    } finally {
        try {
            fin.close();
            fout.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

其他三个copymd、copylg、copyxl方法都做同样的修改,就能保证目标文件和源文件大小完全一致了。

额外优化建议

你的四个复制方法几乎一模一样,完全可以合并成一个通用方法,减少代码冗余。比如:

private static void copyFile(File a, File b, byte[] buffer) {
    try {
        length = a.length();
        fin = new FileInputStream(a);
        fout = new FileOutputStream(b);
        i = fin.read(buffer);
        j = 0;
        while (i != -1) {
            j += i;
            fout.write(buffer, 0, i);
            System.out.print("Copying... " + decimal_p_.format(((j / length) * 100)) + " " + a.getName() + " to " + b.getPath() + " buffer: " + buffer.length + " \r");
            i = fin.read(buffer);
        }
    } catch (Exception e) {
        System.out.println(e.getMessage());
        e.printStackTrace();
    } finally {
        try {
            if (fin != null) fin.close();
            if (fout != null) fout.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后在main方法里直接调用这个通用方法:

public static void main(String[] args) {
    File in = new File(args[0]);
    File out = new File(args[1]);
    double ld = in.length();
    double l = ld / 1024 / 1024;
    byte[] buffer;
    if (l <= ((9 * 1024) / 1024 / 1024)) {
        buffer = buffersm;
    } else if (l <= 9) {
        buffer = buffermd;
    } else if (l <= 99) {
        buffer = bufferlg;
    } else {
        buffer = bufferxl;
    }
    copyFile(in, out, buffer);
    System.out.println();
}

这样代码更简洁,也更容易维护~

内容的提问来源于stack exchange,提问作者Hot4RST

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:09:42