java - 如何在 Java 中复制大于 4.3 GB 的文件

标签 java linux ubuntu-16.04 java-io

我正在编写一个程序部分,只是为了将文件从源文件复制到目标文件。该代码可以正常工作,但如果有一个大文件,则在目标文件达到 4.3 GB 的大小后,复制过程将结束,但有一个异常(exception)。异常(exception)是“文件太大”,它看起来像:

java.io.IOException: Die Datei ist zu groß
at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
at sun.nio.ch.FileDispatcherImpl.write(FileDispatcherImpl.java:60)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:211)
at java.nio.channels.Channels.writeFullyImpl(Channels.java:78)
at java.nio.channels.Channels.writeFully(Channels.java:101)
at java.nio.channels.Channels.access$000(Channels.java:61)
at java.nio.channels.Channels$1.write(Channels.java:174)
at java.nio.file.Files.copy(Files.java:2909)
at java.nio.file.Files.copy(Files.java:3069)
at sample.Controller.copyStream(Controller.java:318)

制作方法如下:

    private void copyStream(File src, File dest){
    try {

        FileInputStream fis = new FileInputStream(src);
        OutputStream newFos = java.nio.file.Files.newOutputStream(dest.toPath(),StandardOpenOption.WRITE);

        Files.copy(src.toPath(),newFos);

        newFos.flush();
        newFos.close();
        fis.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

我也试过用java.io Fileoutputstream,写kbyte的方式,结果还是一样。如何复制或创建大于 4.3 GB 的文件?是否可以使用 Java 以外的其他语言?这个程序我在 Linux (Ubuntu LTS 16.04) 上运行。

提前致谢。


编辑:

非常感谢大家的帮助。正如您所说,文件系统是问题所在。在我将文件系统格式化为 exfat 后,它工作正常。

最佳答案

POSIX(以及 Unix)系统允许对路径(您从 File.getPath() 获得的)或路径的组成部分(最后一个您可以使用 File.getName() 获取)。您可能会遇到此问题,因为文件的名称很长。

在这种情况下,文件 open操作系统调用将失败并返回 ENAMETOOLONG error code .

但是,消息“文件太大”通常与“EFBIG”错误代码相关联。这更有可能是由 write 引起的系统调用:

An attempt was made to write a file that exceeds the implementation-dependent maximum file size or the process' file size limit.

也许正在打开文件进行追加,隐含的 lseek到文件末尾给出了 EFBIG 错误。

最后,如果必须对您的 RAM 执行某些操作,您可以尝试其他复制方法。

另一种可能是磁盘已满。

要复制文件,基本上有四种方式 [事实证明,流是基本级别上最快的]:

使用流复制:

private static void copyFileUsingStream(File source, File dest) throws IOException {
    InputStream is = null;
    OutputStream os = null;
    try {
        is = new FileInputStream(source);
        os = new FileOutputStream(dest);
        byte[] buffer = new byte[1024];
        int length;
        while ((length = is.read(buffer)) > 0) {
            os.write(buffer, 0, length);
        }
    } finally {
      is.close();
      os.close();
    }
}

用 Java NIO 类复制:

private static void copyFileUsingChannel(File source, File dest) throws IOException {
    FileChannel sourceChannel = null;
    FileChannel destChannel = null;
    try {
        sourceChannel = new FileInputStream(source).getChannel();
        destChannel = new FileOutputStream(dest).getChannel();
        destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
    }finally{
           sourceChannel.close();
           destChannel.close();
    }
}

使用 Apache Commons IO FileUtils 复制:

private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
    FileUtils.copyFile(source, dest);
}

以及使用 Java 7 和 Files 类的方法:

private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
    Files.copy(source.toPath(), dest.toPath());
}

编辑 1: 正如评论中所建议的,这里有三个 SO 问题,它们涵盖了问题并更好地解释了四种不同的复制方法:

感谢@jww 指出

关于java - 如何在 Java 中复制大于 4.3 GB 的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52281384/

相关文章:

Java Jar 文件的 java.lang.NoClassDefFoundError

java - 为什么 java 中的 lib func 运行速度比自定义的快?

java - 在自定义 JPanel 和 JTable 布局之间进行选择

linux - awk 脚本匹配模式,然后删除分隔符后的整行

c - 如何使用 linux distro : ubuntu 16. 04 在 c 中使用 API

java - 如何在 Java 中将控制台数据转换为文本文件

linux - 令人困惑的 shell 语法

linux - 自定义 Linux 内核模块来显示年份、日期和时间

docker - 由于 docker/cron,设备上没有剩余空间

node.js - 无法访问 google cloud ubuntu 16.04 实例上的 nodeJS REST API,但我可以成功 ping 公共(public) IP