Files.copy: примеры (JAVA)

Примеры применения Files.copy в Java проектах
Раздел: Файловая система
Files.copy(Path source, Path target): Path

Краткое описание метода

Метод Files.copy из пакета java.nio.file предоставляет несколько перегрузок для копирования данных между файловой системой и потоками. Используется при копировании файлов, записи входного потока в файл или при чтении файла в выходной поток. Подходит для простых операций копирования с возможностью указать поведение при совпадении имен и при сохранении атрибутов.

Доступные перегрузки и их поведение:

  • Path copy(Path source, Path target, CopyOption... options) - копирует файл или символическую ссылку source в target. Возвращает Path целевого файла (обычно target). Параметр CopyOption... принимает значения из java.nio.file.StandardCopyOption, например REPLACE_EXISTING и COPY_ATTRIBUTES. Без опции REPLACE_EXISTING при существующем target бросается FileAlreadyExistsException. Копирование директории обычно не выполняется (бросается IOException).
  • Path copy(InputStream in, Path target, CopyOption... options) - читает данные из потока in и записывает в файл target. Возвращает Path целевого файла. Опции применяются аналогично первой перегрузке (например, перезапись или копирование атрибутов).
  • long copy(Path source, OutputStream out) - читает данные из файла source и записывает их в out. Возвращает количество байт, переданных в выходной поток (long). Опции для этой перегрузки не передаются.

Типичные исключения и возвраты:

  • IOException - общая ошибка ввода-вывода при чтении/записи.
  • FileAlreadyExistsException - цель существует и не задана опция перезаписи.
  • SecurityException - отсутствуют права доступа для чтения/записи.
  • UnsupportedOperationException - запрошенные опции не поддерживаются файловой системой (например, копирование атрибутов на некоторых платформах).

Особенности: метод не выполняет рекурсивное копирование дерева каталогов. Для тонкой настройки поведения лучше вручную обходить структуру файлов и применять Files.copy к каждому файлу.

Небольшие примеры использования

Пример 1: копирование файла в файл с перезаписью и копированием атрибутов

import java.nio.file.*;
import java.nio.file.StandardCopyOption;

Path src = Paths.get("/tmp/source.txt");
Path dst = Paths.get("/tmp/dest.txt");
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
System.out.println("Скопировано");
Скопировано

Пример 2: запись из InputStream в файл

import java.io.*;
import java.nio.file.*;

try (InputStream in = new ByteArrayInputStream("Пример".getBytes())) {
    Path target = Paths.get("/tmp/out.txt");
    Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
    System.out.println("Записан файл " + target);
}
Записан файл /tmp/out.txt

Пример 3: чтение файла в OutputStream и получение количества байт

import java.io.*;
import java.nio.file.*;

Path source = Paths.get("/tmp/source.bin");
ByteArrayOutputStream out = new ByteArrayOutputStream();
long bytes = Files.copy(source, out);
System.out.println("Скопировано байт: " + bytes);
Скопировано байт: 1024

Пример 4: попытка копирования при существующем файле без REPLACE_EXISTING

Path src = Paths.get("/tmp/a.txt");
Path dst = Paths.get("/tmp/b.txt");
Files.copy(src, dst);
java.nio.file.FileAlreadyExistsException: /tmp/b.txt

Похожие решения в Java

  • FileChannel.transferTo/transferFrom - полезны для высокопроизводительного копирования больших файлов, дают контроль над позиционированием и могут быть быстрее в некоторых реализациях.
  • Files.move - при необходимости перемещения файла вместо копирования; поддерживает ATOMIC_MOVE для атомарной замены при поддержке файловой системы.
  • java.io streams (FileInputStream/FileOutputStream) - позволяет реализовать кастомную логику (буферизация, прогресс, сжатие) и контролировать процесс посекторно.
  • Apache Commons IO (FileUtils.copyFile и др.) - удобные утилиты с готовыми проверками и совместимостью с старыми API.

Выбор зависит от требований: для простых операций и сохранения атрибутов удобнее Files.copy, для больших файлов или тонкого контроля по производительности лучше FileChannel или специализированные библиотеки.

Аналоги в других языках

  • PHP: функция copy($src, $dst). Простая в использовании, возвращает true/false. Не сохраняет атрибуты файла автоматически.
  • JavaScript (Node.js): fs.copyFile(src, dest, flags, callback) и синхронный fs.copyFileSync. Поддерживает флаг fs.constants.COPYFILE_EXCL для отказа при существующем файле.
  • Python: модуль shutil - shutil.copy(src, dst), shutil.copy2 (копирует метаданные), shutil.copyfileobj (потоки).
  • C#: System.IO.File.Copy(sourceFileName, destFileName, overwrite). Параметр overwrite управляет перезаписью.
  • Go: обычно используется комбинация io.Copy(dst, src) с открытием файлов через os.Open и os.Create. Возвращает количество байт и ошибку.
  • Kotlin: использует те же API, что и Java (java.nio.file.Files.copy) или расширения для java.io.
  • Lua: нет стандартной функции копирования файлов в базовой библиотеке; обычно выполняется чтение/запись в цикле или используются сторонние модули.
  • SQL: в общем виде не предназначен для работы с файловой системой; в некоторых СУБД есть утилиты для загрузки/выгрузки файлов (LOAD_FILE, BULK INSERT) но это специфично.

Короткие примеры (результаты указаны условно):

Python (shutil.copy2):

import shutil
shutil.copy2('/tmp/a.txt', '/tmp/b.txt')
print('ok')
ok

Node.js (fs.copyFileSync):

const fs = require('fs');
fs.copyFileSync('/tmp/a.txt', '/tmp/b.txt');
console.log('copied');
copied

Go (io.Copy):

f1, _ := os.Open("/tmp/a.txt")
f2, _ := os.Create("/tmp/b.txt")
bytes, _ := io.Copy(f2, f1)
fmt.Println("bytes:", bytes)
bytes: 2048

Типичные ошибки и их проявления

Пример 1: попытка копирования при существующем файле без опции перезаписи. Результат - исключение FileAlreadyExistsException.

Path src = Paths.get("/tmp/a.txt");
Path dst = Paths.get("/tmp/b.txt");
Files.copy(src, dst);
java.nio.file.FileAlreadyExistsException: /tmp/b.txt
	at ...

Пример 2: недостаток прав на запись. Результат - AccessDeniedException или IOException.

Path src = Paths.get("/etc/passwd");
Path dst = Paths.get("/root/out.txt");
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);
java.nio.file.AccessDeniedException: /root/out.txt

Пример 3: попытка копирования директории. Обычно возникает IOException или специфичное исключение файловой системы.

Path dir = Paths.get("/tmp/mydir");
Path dst = Paths.get("/tmp/mydir_copy");
Files.copy(dir, dst);
java.io.IOException: Unable to copy directory

Рекомендации по отладке ошибок: проверка прав доступа, существования пути, корректности типов (файл/директория) и поддерживаемых опций файловой системы.

Изменения и история

Метод Files.copy появился в Java 7 вместе с NIO.2 и в целом сохраняет обратную совместимость. Новые версии Java не вносили значительных изменений в сигнатуры. Развитие затрагивало в основном поведение на разных реализациях файловых систем и улучшения безопасности платформы. Для сохранения метаданных применяется StandardCopyOption.COPY_ATTRIBUTES, но поддержка конкретных атрибутов зависит от ОС и реализации.

Расширенные и необычные сценарии

1) Копирование с отслеживанием прогресса и поддержкой отмены. Используется FileChannel.transferTo и периодическая проверка флага отмены.

Пример java
import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;

Path src = Paths.get("/tmp/large.bin");
Path tmp = Paths.get("/tmp/large.bin.part");
try (FileChannel in = FileChannel.open(src, StandardOpenOption.READ);
     FileChannel out = FileChannel.open(tmp, StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    long size = in.size();
    long pos = 0;
    while (pos < size) {
        long transferred = in.transferTo(pos, Math.min(8 * 1024 * 1024, size - pos), out);
        pos += transferred;
        System.out.printf("Скопировано %%d/%%d\n", pos, size);
        // здесь возможна проверка внешнего флага отмены
    }
    Files.move(tmp, Paths.get("/tmp/large.bin.copy"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
}
Скопировано 8388608/104857600
Скопировано 16777216/104857600
...

2) Атомарическая замена существующего файла: сначала запись во временный файл, затем переименование с ATOMIC_MOVE.

Пример java
Path src = Paths.get("/tmp/source.txt");
Path tmp = Paths.get("/tmp/dest.txt.tmp");
Path dst = Paths.get("/tmp/dest.txt");
Files.copy(src, tmp, StandardCopyOption.REPLACE_EXISTING);
Files.move(tmp, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
(выполнено без видимой промежуточной стадии для других процессов при поддержке FS)

3) Копирование символической ссылки как ссылки (в некоторых реализациях): в зависимости от файловой системы и передачи опций поведение может отличаться. Для универсального результата можно прочитать ссылку и создать новую ссылку вручную.

Пример java
Path link = Paths.get("/tmp/mylink");
Path target = Paths.get("/tmp/mylink_copy");
if (Files.isSymbolicLink(link)) {
    Path pointed = Files.readSymbolicLink(link);
    Files.createSymbolicLink(target, pointed);
}
(создана новая символическая ссылка, указывающая на тот же путь)

4) Копирование с трансформацией потока: чтение, сжатие и запись в целевой файл.

Пример java
import java.util.zip.GZIPOutputStream;

try (InputStream in = Files.newInputStream(Paths.get("/tmp/data.txt"));
     OutputStream fout = Files.newOutputStream(Paths.get("/tmp/data.txt.gz"));
     GZIPOutputStream gz = new GZIPOutputStream(fout)) {
    byte[] buf = new byte[8192];
    int r;
    while ((r = in.read(buf)) > 0) {
        gz.write(buf, 0, r);
    }
}
System.out.println("Сжатие выполнено");
Сжатие выполнено

5) Копирование по сети через NIO: чтение файла в ByteBuffer и отправка через SocketChannel, на приёмной стороне запись через Files.copy (посредством OutputStream).

Примеры показывают разные сценарии: от простых копирований до атомарных замен и потоковой трансформации. При работе с большим объёмом данных рекомендуется тестировать производительность и учитывать особенности платформы.

джава Files.copy function comments

En
Files.copy Копирует файл или директорию