Стандартный краткий способ скопировать файл в Java? - PullRequest
414 голосов
/ 20 сентября 2008

Меня всегда беспокоило, что единственный способ скопировать файл на Java - это открыть потоки, объявить буфер, прочитать один файл, пройти по нему и записать его в другой поток. Сеть изобилует похожими, но все же немного отличающимися реализациями этого типа решения.

Есть ли лучший способ, который остается в пределах языка Java (то есть не подразумевает выполнение специфичных для ОС команд)? Возможно, в каком-нибудь надежном пакете утилит с открытым исходным кодом, который, по крайней мере, затмит эту базовую реализацию и обеспечит однострочное решение?

Ответы [ 16 ]

276 голосов
/ 22 сентября 2008

Я бы избегал использования мега-API, как Apache Commons. Это упрощенная операция, встроенная в JDK в новом пакете NIO. Это уже было похоже на предыдущий ответ, но ключевым методом в API-интерфейсе NIO являются новые функции «TransferTo» и «TransferFrom».

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html#transferTo(long,%20long,%20java.nio.channels.WritableByteChannel)

Одна из связанных статей демонстрирует отличный способ интеграции этой функции в ваш код с помощью TransferFrom:

public static void copyFile(File sourceFile, File destFile) throws IOException {
    if(!destFile.exists()) {
        destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;

    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    }
    finally {
        if(source != null) {
            source.close();
        }
        if(destination != null) {
            destination.close();
        }
    }
}

Изучение NIO может быть немного сложнее, поэтому вы можете просто довериться этому механику, прежде чем уйти и попытаться изучить NIO в одночасье. Из личного опыта очень трудно научиться, если у вас нет такого опыта и вы познакомились с IO через потоки java.io.

272 голосов
/ 20 сентября 2008

Как уже упоминалось выше, Apache Commons IO - это путь, в частности FileUtils . copyFile () ; он берет на себя всю тяжелую работу за вас.

И, как постскриптум, обратите внимание, что в последних версиях FileUtils (таких как выпуск 2.0.1) добавлено использование NIO для копирования файлов; NIO может значительно повысить производительность копирования файлов , в значительной степени потому, что процедуры NIO откладывают копирование непосредственно в ОС / файловую систему, а не обрабатывают его путем чтения и записи байтов через уровень Java. Поэтому, если вы ищете производительность, возможно, стоит проверить, используете ли вы последнюю версию FileUtils.

179 голосов
/ 28 июля 2011

Теперь в Java 7 вы можете использовать следующий синтаксис try-with-resource:

public static void copyFile( File from, File to ) throws IOException {

    if ( !to.exists() ) { to.createNewFile(); }

    try (
        FileChannel in = new FileInputStream( from ).getChannel();
        FileChannel out = new FileOutputStream( to ).getChannel() ) {

        out.transferFrom( in, 0, in.size() );
    }
}

Или, что еще лучше, этого также можно достичь с помощью нового класса Files, представленного в Java 7:

public static void copyFile( File from, File to ) throws IOException {
    Files.copy( from.toPath(), to.toPath() );
}

Довольно шикарно, а?

87 голосов
/ 17 мая 2013
  • Эти методы предназначены для повышения производительности (они интегрируются с собственным вводом / выводом операционной системы).
  • Эти методы работают с файлами, каталогами и ссылками.
  • Каждый из представленных вариантов может быть пропущен - они являются необязательными.

Утилита класса

package com.yourcompany.nio;

class Files {

    static int copyRecursive(Path source, Path target, boolean prompt, CopyOptions options...) {
        CopyVisitor copyVisitor = new CopyVisitor(source, target, options).copy();
        EnumSet<FileVisitOption> fileVisitOpts;
        if (Arrays.toList(options).contains(java.nio.file.LinkOption.NOFOLLOW_LINKS) {
            fileVisitOpts = EnumSet.noneOf(FileVisitOption.class) 
        } else {
            fileVisitOpts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        }
        Files.walkFileTree(source[i], fileVisitOpts, Integer.MAX_VALUE, copyVisitor);
    }

    private class CopyVisitor implements FileVisitor<Path>  {
        final Path source;
        final Path target;
        final CopyOptions[] options;

        CopyVisitor(Path source, Path target, CopyOptions options...) {
             this.source = source;  this.target = target;  this.options = options;
        };

        @Override
        FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
        // before visiting entries in a directory we copy the directory
        // (okay if directory already exists).
        Path newdir = target.resolve(source.relativize(dir));
        try {
            Files.copy(dir, newdir, options);
        } catch (FileAlreadyExistsException x) {
            // ignore
        } catch (IOException x) {
            System.err.format("Unable to create: %s: %s%n", newdir, x);
            return SKIP_SUBTREE;
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        Path newfile= target.resolve(source.relativize(file));
        try {
            Files.copy(file, newfile, options);
        } catch (IOException x) {
            System.err.format("Unable to copy: %s: %s%n", source, x);
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
        // fix up modification time of directory when done
        if (exc == null && Arrays.toList(options).contains(COPY_ATTRIBUTES)) {
            Path newdir = target.resolve(source.relativize(dir));
            try {
                FileTime time = Files.getLastModifiedTime(dir);
                Files.setLastModifiedTime(newdir, time);
            } catch (IOException x) {
                System.err.format("Unable to copy all attributes to: %s: %s%n", newdir, x);
            }
        }
        return CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException exc) {
        if (exc instanceof FileSystemLoopException) {
            System.err.println("cycle detected: " + file);
        } else {
            System.err.format("Unable to copy: %s: %s%n", file, exc);
        }
        return CONTINUE;
    }
}

Копирование каталога или файла

long bytes = java.nio.file.Files.copy( 
                 new java.io.File("<filepath1>").toPath(), 
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING,
                 java.nio.file.StandardCopyOption.COPY_ATTRIBUTES,
                 java.nio.file.LinkOption.NOFOLLOW_LINKS);

Перемещение каталога или файла

long bytes = java.nio.file.Files.move( 
                 new java.io.File("<filepath1>").toPath(), 
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.ATOMIC_MOVE,
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING);

Рекурсивное копирование каталога или файла

long bytes = com.yourcompany.nio.Files.copyRecursive( 
                 new java.io.File("<filepath1>").toPath(), 
                 new java.io.File("<filepath2>").toPath(),
                 java.nio.file.StandardCopyOption.REPLACE_EXISTING,
                 java.nio.file.StandardCopyOption.COPY_ATTRIBUTES
                 java.nio.file.LinkOption.NOFOLLOW_LINKS );
39 голосов
/ 20 июня 2014

В Java 7 это просто ...

File src = new File("original.txt");
File target = new File("copy.txt");

Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
28 голосов
/ 23 октября 2013

Чтобы скопировать файл и сохранить его по пути назначения, вы можете использовать метод ниже.

public void copy(File src, File dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}
24 голосов
/ 23 сентября 2008

Обратите внимание, что все эти механизмы копируют только содержимое файла, а не метаданные, такие как разрешения. Таким образом, если вы скопируете или переместите исполняемый файл .sh в Linux, новый файл не будет исполняемым.

Чтобы действительно скопировать или переместить файл, то есть получить тот же результат, что и при копировании из командной строки, вам на самом деле нужно использовать встроенный инструмент. Либо сценарий оболочки, либо JNI.

По-видимому, это может быть исправлено в Java 7 - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html. Скрещенные пальцы!

22 голосов
/ 05 июля 2010

В библиотеке Google Guava также есть метод копирования :

public static void copy(File from,
                        File to)
                 throws IOException
Копирует все байты из одного файла в другой.

Предупреждение: Если to представляет существующий файл, этот файл будет перезаписано содержимым from. Если to и from см. тот же файл , содержимое этого файла будут удалены.

19 голосов
/ 01 июня 2010

Доступно как стандарт в Java 7, path.copyTo: http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.html http://java.sun.com/docs/books/tutorial/essential/io/copy.html

Не могу поверить, что им потребовалось так много времени, чтобы стандартизировать что-то такое простое и простое, как копирование файлов: (

7 голосов
/ 13 ноября 2014

Вот три способа, которыми вы можете легко скопировать файлы с помощью одной строки кода!

Java7

java.nio.file.Files # копия

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

Appache Commons IO :

FileUtils # CopyFile

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

Гуава :

Files # копия

private static void copyFileUsingGuava(File source,File dest) throws IOException{
    Files.copy(source,dest);          
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...