Стандартный сжатый способ копирования файла на Java?
Меня всегда беспокоило, что единственный способ скопировать файл в Java включает в себя открытие потоков, объявление буфера, чтение в одном файле, прохождение через него и запись его на другой пар. Сеть усеяна подобными, но все же немного отличающимися реализациями этого типа решений.
Есть ли лучший способ, который остается в пределах языка Java (это означает, что не требуется выполнение определенных команд ОС)? Возможно, в каком-то надежном программном пакете с открытым исходным кодом, который по крайней мере заслонит эту базовую реализацию и предоставит однострочное решение?
Ответы
Ответ 1
В качестве упоминаемого выше инструментария Apache Commons IO - это путь, в частности FileUtils. CopyFile(); он обрабатывает весь тяжелый подъем для вас.
И в качестве постскриптума обратите внимание, что последние версии FileUtils (например, выпуск 2.0.1) добавили использование NIO для копирования файлов; NIO может значительно увеличить производительность копирования файлов, в значительной степени потому, что процедуры NIO откладывают копирование непосредственно в OS/файловую систему, а не обрабатывают ее, читая и записывая байты через уровень Java. Поэтому, если вы ищете производительность, возможно, стоит проверить, что вы используете последнюю версию FileUtils.
Ответ 2
Я бы избегал использования мега api, как apache. Это упрощенная операция и ее встроенная в 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.io.
Ответ 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("<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 );
Ответ 5
В Java 7 легко...
File src = new File("original.txt");
File target = new File("copy.txt");
Files.copy(src.toPath(), target.toPath(), StandardCopyOption.REPLACE_EXISTING);
Ответ 6
Чтобы скопировать файл и сохранить его на пути назначения, вы можете использовать метод ниже.
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();
}
}
Ответ 7
Обратите внимание, что все эти механизмы копируют только содержимое файла, а не метаданные, такие как разрешения. Поэтому, если вы хотите скопировать или переместить исполняемый файл .sh в linux, новый файл не будет исполняться.
Чтобы действительно копировать или перемещать файл, т.е. получить тот же результат, что и копирование из командной строки, вам действительно нужно использовать собственный инструмент. Либо оболочка script, либо JNI.
По-видимому, это может быть исправлено в java 7 - http://today.java.net/pub/a/today/2008/07/03/jsr-203-new-file-apis.html. Пальцы скрещены!
Ответ 8
В библиотеке Google Guava также есть метод копирования:
public static void copy ( Файл from, Файл в) throws IOException
- Копирует все байты из одного файла в другой.
Предупреждение: Если to
представляет существующий файл, этот файл
будет перезаписано содержимым from
. Если to
и
from
ссылаются на тот же файл, содержимое этого файла
будет удален.
Параметры: из
- исходный файл в
- файл назначения
Выдает:
IOException
- если возникает ошибка ввода-вывода
IllegalArgumentException
- если from.equals(to)
Ответ 9
Доступен в качестве стандарта в Java 7, путь .copyTo:
http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path.html
http://java.sun.com/docs/books/tutorial/essential/io/copy.html
Я не могу поверить, что им потребовалось столько времени, чтобы стандартизировать что-то настолько распространенное и простое, как копирование файлов: (
Ответ 10
Три возможных проблемы с приведенным выше кодом:
- Если getChannel выдает исключение, вы можете протекать открытым потоком.
- Для больших файлов может потребоваться передача большего количества времени, чем может обрабатывать ОС.
- Вы игнорируете возвращаемое значение transferFrom, поэтому оно может копировать только часть файла.
Вот почему org.apache.tools.ant.util.ResourceUtils.copyResource
настолько сложна. Также обратите внимание, что while transferFrom в порядке, transferTo разбивается на JDK 1.4 на Linux (см. Идентификатор ошибки: 5056395) - Джесси Глик Ян
Ответ 11
Если вы используете веб-приложение, которое уже использует Spring, и если вы не хотите включать Apache Commons IO для простого копирования файлов, вы можете использовать FileCopyUtils рамки Spring.
Ответ 12
Вот три способа, которыми вы можете легко скопировать файлы с помощью одной строки кода!
Java7
java.nio.file.Files # copy
private static void copyFileUsingJava7Files(File source, File dest) throws IOException {
Files.copy(source.toPath(), dest.toPath());
}
Appomm Commons IO:
FileUtils # copyFile
private static void copyFileUsingApacheCommonsIO(File source, File dest) throws IOException {
FileUtils.copyFile(source, dest);
}
Гуава:
Файлы # copy
private static void copyFileUsingGuava(File source,File dest) throws IOException{
Files.copy(source,dest);
}
Ответ 13
public static void copyFile(File src, File dst) throws IOException
{
long p = 0, dp, size;
FileChannel in = null, out = null;
try
{
if (!dst.exists()) dst.createNewFile();
in = new FileInputStream(src).getChannel();
out = new FileOutputStream(dst).getChannel();
size = in.size();
while ((dp = out.transferFrom(in, p, size)) > 0)
{
p += dp;
}
}
finally {
try
{
if (out != null) out.close();
}
finally {
if (in != null) in.close();
}
}
}
Ответ 14
Быстро и работайте со всеми версиями Java и Android:
private void copy(final File f1, final File f2) throws IOException {
f2.createNewFile();
final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");
file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));
file1.close();
file2.close();
}
Ответ 15
Копирование NIO с буфером является самым быстрым в соответствии с моим тестом. См. Рабочий код ниже из моего тестового проекта на https://github.com/mhisoft/fastcopy
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DecimalFormat;
public class test {
private static final int BUFFER = 4096*16;
static final DecimalFormat df = new DecimalFormat("#,###.##");
public static void nioBufferCopy(final File source, final File target ) {
FileChannel in = null;
FileChannel out = null;
double size=0;
long overallT1 = System.currentTimeMillis();
try {
in = new FileInputStream(source).getChannel();
out = new FileOutputStream(target).getChannel();
size = in.size();
double size2InKB = size / 1024 ;
ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER);
while (in.read(buffer) != -1) {
buffer.flip();
while(buffer.hasRemaining()){
out.write(buffer);
}
buffer.clear();
}
long overallT2 = System.currentTimeMillis();
System.out.println(String.format("Copied %s KB in %s millisecs", df.format(size2InKB), (overallT2 - overallT1)));
}
catch (IOException e) {
e.printStackTrace();
}
finally {
close(in);
close(out);
}
}
private static void close(Closeable closable) {
if (closable != null) {
try {
closable.close();
} catch (IOException e) {
if (FastCopy.debug)
e.printStackTrace();
}
}
}
}