Вопрос-ответ

Standard concise way to copy a file in Java?

Стандартный краткий способ скопировать файл на Java?

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

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

Переведено автоматически
Ответ 1

Я бы избегал использования mega api, такого как apache commons. Это упрощенная операция, и она встроена в JDK в новом пакете NIO. Вроде как на это уже была ссылка в предыдущем ответе, но ключевым методом в NIO api являются новые функции "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.потоки ввода / вывода.

Ответ 2

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

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

Ответ 3

Теперь в 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() );
}

Шикарно, да?

Ответ 4

  • Эти методы оптимизированы для повышения производительности (они интегрируются с собственным вводом-выводом операционной системы).

  • Эти методы работают с файлами, каталогами и ссылками.

  • Каждый из предоставленных параметров может быть опущен - они необязательны.

Служебный класс

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("<filepath3>").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("<filepath3>").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("<filepath3>").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 );
java file