Как скопировать файл на Java

Копирование файлов в Java Копирование файла или каталога было типичной задачей разработки. С появлением контейнеров Docker и стремлением к максимальной неизменяемости мы видим это все реже и реже. Тем не менее, это фундаментальная концепция, и было бы полезно знать, какие варианты есть у разработчика, когда им нужно скопировать файл. Потоки ввода-вывода До Java 1.5 стандартным способом копирования файла было использование потоков ввода-вывода [https://docs.oracle.com/javase/tutorial/essential/io/streams.html]: pr

Копирование файлов на Java

Копирование файла или каталога было типичной задачей разработки. С появлением контейнеров Docker и стремлением к максимальной неизменяемости мы видим это все реже и реже.

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

Потоки ввода / вывода

До Java 1.5 стандартным способом копирования файла было использование потоков ввода-вывода :

 private void copyFile(File src, File dest) throws IOException { 
 InputStream inputStream = null; 
 OutputStream outputStream = null; 
 try { 
 inputStream = new FileInputStream(source); 
 outputStream = new FileOutputStream(dest); 
 
 // the size of the buffer doesn't have to be exactly 1024 bytes, try playing around with this number and see what effect it will have on the performance 
 byte[] buffer = new byte[1024]; 
 int length = 0; 
 while ((length = is.read(buffer)) > 0) { 
 os.write(buffer, 0, length); 
 } 
 } finally { 
 is.close(); 
 os.close(); 
 } 
 } 

Каналы и java.nio

После крупного рефакторинга платформы Java и выпуска Java 1.4 в 2000 году был представлен java.nio

Процесс File стал выглядеть более элегантно и компактно:

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

Наиболее заметное отличие состоит в том, что мы избавились от цикла while и больше не контролируем размер буфера напрямую.

Класс помощника по файлам

Вместе с Java 7, выпущенной в 2011 году, был добавлен вспомогательный класс, позволяющий копировать файлы в одну строку кода:

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

Взглянув на документацию по API, мы видим, что можно предоставить дополнительную опцию для метода copy()

Поддерживаются следующие параметры из перечислений StandardCopyOption и LinkOption :

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

  • COPY_ATTRIBUTES - копирует атрибуты файла, связанные с файлом, в целевой файл. Точные поддерживаемые атрибуты файлов зависят от файловой системы и платформы, но время последнего изменения поддерживается на всех платформах и копируется в целевой файл.

  • NOFOLLOW_LINKS - указывает, что по символическим ссылкам не следует переходить. Если файл, который нужно скопировать, является символической ссылкой, копируется ссылка (а не цель ссылки).

Apache Commons IO и Google Guava

Эти две очень удобные вспомогательные библиотеки предоставляют очень похожий API для копирования файлов. Единственным недостатком использования любого из них является необходимость добавления в проект .jar

Но если он уже там, то почему бы и нет?

 private void copyFileApacheCommons(File src, File dest) throws IOException { 
 FileUtils.copyFile(src, dest); 
 } 

 private void copyFileGoogleGuava(File src, File dest) throws IOException { 
 Files.copy(src, dest); 
 } 

Бонус

Подождите, но что у меня есть String, представляющий имя файла, а не фактический объект File?

Не беспокойтесь, у нас это есть!

 private File filenameToFile(String filename) throws IOException { 
 return new File(filename); 
 } 

Какой из них использовать?

Потоки и каналы ввода-вывода

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

Другой вариант - если вы работаете над унаследованным проектом с устаревшей версией Java, и его обновление невозможно. Во всех остальных случаях вы должны проверить, есть ли Apache Commons или Google Guava уже в списке зависимостей, и выбрать одну из них.

Если это не так, вам не следует добавлять их ради этого единственного служебного метода и использовать вспомогательный класс Files

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus