关于FileChannel的transferTo方法复制超过2GB文件不完整的情况

详情查看FileChannelImpl的transferTo的实现源码

public long transferTo(long var1, long var3, WritableByteChannel var5) throws IOException {
        this.ensureOpen();
        if (!var5.isOpen()) {
            throw new ClosedChannelException();
        } else if (!this.readable) {
            throw new NonReadableChannelException();
        } else if (var5 instanceof FileChannelImpl && !((FileChannelImpl)var5).writable) {
            throw new NonWritableChannelException();
        } else if (var1 >= 0L && var3 >= 0L) {
            long var6 = this.size();
            if (var1 > var6) {
                return 0L;
            } else {
                int var8 = (int)Math.min(var3, 2147483647L);
                if (var6 - var1 < (long)var8) {
                    var8 = (int)(var6 - var1);
                }

                long var9;
                if ((var9 = this.transferToDirectly(var1, var8, var5)) >= 0L) {
                    return var9;
                } else {
                    return (var9 = this.transferToTrustedChannel(var1, (long)var8, var5)) >= 0L ? var9 : this.transferToArbitraryChannel(var1, var8, var5);
                }
            }
        } else {
            throw new IllegalArgumentException();
        }
    }

主要查看倒数第二个判断里的代码

else if (var1 >= 0L && var3 >= 0L) {
            long var6 = this.size();
            if (var1 > var6) {
                return 0L;
            } else {
                int var8 = (int)Math.min(var3, 2147483647L);
                if (var6 - var1 < (long)var8) {
                    var8 = (int)(var6 - var1);
                }

                long var9;
                if ((var9 = this.transferToDirectly(var1, var8, var5)) >= 0L) {
                    return var9;
                } else {
                    return (var9 = this.transferToTrustedChannel(var1, (long)var8, var5)) >= 0L ? var9 : this.transferToArbitraryChannel(var1, var8, var5);
                }
            }
        } 

var 8 就是 transferToDirectly 方法的单次处理长度,会对传入的var3(也就是由外部传入的 count 参数,即transferTo的第二个参数)

进行Math.min判断,而2147483647L 其实是字节,也就是2GB - 1个字节的长度,这就是transferTo单次处理长度的极限长度

所以如果处理超过2GB的文件就要循环执行transferTo方法,直至处理长度和文件长度一样为止

附上简易的处理方法

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

/**
 * author: GoL
 * time:   2018-11-24 0024
 */
public class CopyFile {
    public static void main(String[] args) {
        File source = new File("I:\\fileSize4GB.txt");
        File target = new File("G:\\test.txt");
        try (FileInputStream is = new FileInputStream(source); FileChannel in = is.getChannel();
             FileOutputStream os = new FileOutputStream(target); FileChannel out = os.getChannel()) {
            int position = 0;
            long size = in.size();
            while (0 < size) {
                long count = in.transferTo(position, size, out);
                if (count > 0) {
                    position += count;
                    size -= count;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

关于FileChannel的transferTo方法复制超过2GB文件不完整的情况_第1张图片如果帮到你,请点个赞吧 O(∩_∩)O~

你可能感兴趣的:(Java)