В приложениях Java стандартный ввод-вывод происходит в основном между источником ввода и целью вывода. Аналогично, в NIO нам может потребоваться передавать данные из одного канала в другой очень часто. Класс FileChannel в Java NIO предоставляет эффективные методы передачи данных с использованием методов transferTo() и transferFrom().
При использовании методов TransferTo() и TransferFrom() FileChannel данные не проходят через кучу Java, что снижает нагрузку на сборку мусора.
1. Передача данных между каналами
Массовые передачи файловых данных из одного места в другое настолько распространены, что в класс FileChannel было добавлено несколько методов оптимизации, чтобы сделать его еще более эффективным. Два таких метода:
- FileChannel.transferTo()
- FileChannel.transferFrom()
Эти методы обычно используются для высокопроизводительных операций файлового ввода-вывода для перемещения данных между файловыми каналами или между файловым каналом и другими типами каналов(например, каналами сокетов).
Методы transferTo() и transferFrom() позволяют нам осуществлять перекрестное соединение одного канала с другим, устраняя необходимость передачи данных через промежуточный буфер.
Эти методы существуют только в классе FileChannel, поэтому одним из каналов, участвующих в передаче между каналами, должен быть FileChannel.
public abstract class FileChannelextends AbstractChannelimplements ByteChannel, GatheringByteChannel, ScatteringByteChannel {// ... more methods ...public abstract long transferTo(long position, long count, WritableByteChannel target);public abstract long transferFrom(ReadableByteChannel src, long position, long count);}
Мы не можем осуществлять прямую передачу данных между каналами сокетов, но каналы сокетов реализуют WritableByteChannel и ReadableByteChannel, поэтому содержимое файла можно передать в сокет с помощью transferTo(), или данные можно считывать из сокета напрямую в файл с помощью transferFrom().
Также имейте в виду, что эти методы могут выдать исключение java.io.IOException, если во время передачи возникнет какая-либо ошибка.
Передачи между каналами потенциально могут быть чрезвычайно быстрыми, особенно там, где базовая операционная система обеспечивает собственную поддержку. Некоторые операционные системы могут выполнять прямые передачи, не передавая данные через пространство пользователя. Это может быть огромным выигрышем для передачи больших объемов данных.
2. Примеры TransferTo() и TransferFrom() FileChannel
2.1 Простой пример копирования файла
Следующая программа показывает использование методов transferTo() и transferFrom() для копирования файла. Вы можете раскомментировать нужный метод для использования.
import java.io.IOException;import java.nio.channels.FileChannel;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;public class FileCopyExample {public static void main(String[] args) throws IOException {try(FileChannel sourceChannel = FileChannel.open(Paths.get("source.txt"), StandardOpenOption.READ);FileChannel destChannel = FileChannel.open(Paths.get("destination.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE)) {// Using transferTolong size = sourceChannel.size();long position = 0;while(position < size) {position += sourceChannel.transferTo(position, size - position, destChannel);}// Alternatively, using transferFrom// destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());}}}
2.2 Объединение содержимого из нескольких файлов в один
В этом примере мы считываем содержимое трех разных файлов и записываем их объединенный вывод в четвертый файл.
import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.nio.channels.FileChannel;import java.nio.channels.WritableByteChannel;public class ChannelTransferExample {public static void main(String[] argv) throws Exception {//Input filesString[] inputFiles = new String[]{"inputFile1.txt","inputFile2.txt","inputFile3.txt"};//Files contents will be written in these filesString outputFile = "outputFile.txt";//Get channel for output fileFileOutputStream fos = new FileOutputStream(new File(outputFile));WritableByteChannel targetChannel = fos.getChannel();for(int i = 0; i < inputFiles.length; i++) {//Get channel for input filesFileInputStream fis = new FileInputStream(inputFiles[i]);FileChannel inputChannel = fis.getChannel();//Transfer data from input channel to output channelinputChannel.transferTo(0, inputChannel.size(), targetChannel);//close the input channelinputChannel.close();fis.close();}//finally close the target channeltargetChannel.close();fos.close();}}
Оставляйте свои комментарии и предложения в разделе комментариев.