Progress-servis55.ru

Новости из мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Java nio channels

Java IO Tutorial — Java Channels

A channel is an open connection between a data source and a Java program to perform I/O operations.

The Channel interface is in the java.nio.channels package.

Channel interface declares only two methods: close() and isOpen().

Various Channels

A ReadableByteChannel is used to read data from a data source into a byte buffer using its read() method. A WritableByteChannel is used to write data from a byte buffer to a data sink using its write() method.

A ByteChannel is capable of both reading and writing byte data using its read() and write() methods, respectively.

A ScatteringByteChannel reads data from a data source into multiple byte buffers. It is useful to read data from a known file format or a similar data source, where data is supplied in some fixed-length headers followed by a variable length body.

A GatheringByteChannel writes out data from multiple byte buffers.

Create Channels

To obtain a channel, create an object of InputStream and OutputStream using old ways of working with I/O using classes in the java.io package.

The Channels class in the java.nio.channels package is a utility class that has many static methods to convert streams into channels and vice versa.

The Channels class also provides methods to convert readers/writers to channels and vice versa.

For example, if we have an input stream object named myInputStream, we can obtain a ReadableByteChannel as follows:

If we have a ReadableByteChannel named rbc, we can obtain the underlying InputStream object as follows:

FileInputStream and FileOutputStream classes have a new method called getChannel() to return a FileChannel object.

A FileChannel is used to read and write data to a file.

The FileChannel object obtained from a FileInputStream is opened in a read-only mode.

A FileChannel object obtained from a FileOutputStream object is opened in a write-only mode.

If we obtain a FileChannel from a RandomAccessFile, it is opened in a read-only, write-only, or read-write mode, depending on the way we create that RandomAccessFile object.

The following code obtains FileChannel objects for different kinds of file streams:

Reading/Writing Files

A FileChannel object maintains a position variable as a buffer does.

The read() and write() methods for FileChannel come in two varieties: relative position read/write and absolute position read/write.

When we open a FileChannel, its position is set to 0, which is the beginning of the file.

When we read from a FileChannel using a relative read() method, its position is incremented by the number of bytes read.

An absolute position read from a FileChannel does not affect its position.

We can get the current value of the position of a FileChannel object using its position() method.

We can set its position to a new position using its position(int newPosition) method.

Channels are also AutoCloseable. If we use a try-with-resources statement to obtain a channel, the channel will be closed automatically, thus avoiding a need for we to call the close() method of the channel explicitly.

The following code reads text from a file named test1.txt.

The code above generates the following result.

Example

The following code shows how to write to a File Using a Buffer and a Channel.

Copying Contents of a File

We can use buffers and channels to copy a file.

Get the FileChannel object for the source file and the destination file, and call the transferTo() method on the source FileChannel object or call the transferFrom() method on the destination FileChannel object.

The following code shows how to copy a file.

Основные отличия Java IO и Java NIO

Когда я начал изучать стандартный ввод/вывод в Java, то первое время был немного шокирован обилием интерфейсов и классов пакета java.io.*, дополненных еще и целым перечнем специфических исключений.

Потратив изрядное количество часов на изучение и реализацию кучи разнообразных туториалов из Интернета, начал чувствовать себя уверенно и вздохнул с облегчением. Но в один прекрасный момент понял, что для меня все только начинается, так как существует еще и пакет java.nio.*, известный ещё под названием Java NIO или Java New IO. Вначале казалось, что это тоже самое, ну типа вид сбоку. Однако, как оказалось, есть существенные отличия, как в принципе работы, так и в решаемых с их помощью задачах.

Разобраться во всем этом мне здорово помогла статья Джакоба Дженкова (Jakob Jenkov) – “Java NIO vs. IO”. Ниже она приводиться в адаптированном виде.

Поспешу заметить, что статья не является руководством по использованию Java IO и Java NIO. Её цель – дать людям, начинающим изучать Java, возможность понять концептуальные отличия между двумя указанными инструментами организации ввода/вывода.

Основные отличия между Java IO и Java NIO

IONIO
ПотокоориентированныйБуфер-ориентированный
Блокирующий (синхронный) ввод/выводНеблокирующий (асинхронный) ввод/вывод
Селекторы

Потокоориентированный и буфер-ориентированный ввод/вывод

Основное отличие между двумя подходами к организации ввода/вывода в том, что Java IO является потокоориентированным, а Java NIO – буфер-ориентированным. Разберем подробней.

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

Подход, на котором основан Java NIO немного отличается. Данные считываются в буфер для последующей обработки. Вы можете двигаться по буферу вперед и назад. Это дает немного больше гибкости при обработке данных. В то же время, вам необходимо проверять содержит ли буфер необходимый для корректной обработки объем данных. Также необходимо следить, чтобы при чтении данных в буфер вы не уничтожили ещё не обработанные данные, находящиеся в буфере.

Блокирующий и неблокирующий ввод/вывод

Потоки ввода/вывода (streams) в Java IO являются блокирующими. Это значит, что когда в потоке выполнения (tread) вызывается read() или write() метод любого класса из пакета java.io.*, происходит блокировка до тех пор, пока данные не будут считаны или записаны. Поток выполнения в данный момент не может делать ничего другого.

Неблокирующий режим Java NIO позволяет запрашивать считанные данные из канала (channel) и получать только то, что доступно на данный момент, или вообще ничего, если доступных данных пока нет. Вместо того, чтобы оставаться заблокированным пока данные не станут доступными для считывания, поток выполнения может заняться чем-то другим.

Каналы – это логические (не физические) порталы, через которые осуществляется ввод/вывод данных, а буферы являются источниками или приёмниками этих переданных данных. При организации вывода, данные, которые вы хотите отправить, помещаются в буфер, а он передается в канал. При вводе, данные из канала помещаются в предоставленный вами буфер.

Каналы напоминают трубопроводы, по которым эффективно транспортируются данные между буферами байтов и сущностями по ту сторону каналов. Каналы – это шлюзы, которые позволяют получить доступ к сервисам ввода/вывода операционной системы с минимальными накладными расходами, а буферы – внутренние конечные точки этих шлюзов, используемые для передачи и приема данных.

Тоже самое справедливо и для неблокирующего вывода. Поток выполнения может запросить запись в канал некоторых данных, но не дожидаться при этом пока они не будут полностью записаны.

Таким образом неблокирующий режим Java NIO позволяет использовать один поток выполнения для решения нескольких задач вместо пустого прожигания времени на ожидание в заблокированном состояний. Наиболее частой практикой является использование сэкономленного времени работы потока выполнения на обслуживание операций ввода/вывода в другом или других каналах.

Читать еще:  Интерполяция строк javascript

Селекторы

Селекторы в Java NIO позволяют одному потоку выполнения мониторить несколько каналов ввода. Вы можете зарегистрировать несколько каналов с селектором, а потом использовать один поток выполнения для обслуживания каналов, имеющих доступные для обработки данные, или для выбора каналов, готовых для записи.

Чтобы лучше понять концепцию и выгоду от применения селекторов, давайте абстрагируемся от программирования и представим себе железнодорожный вокзал. Вариант без селектора: есть три железнодорожных пути (каналы), на каждый из них в любой момент времени может прибыть поезд (данные из буфера), на каждом пути постоянно ожидает сотрудник вокзала (поток выполнения), задача которого – обслуживание прибывшего поезда. В результате трое сотрудников постоянно находятся на вокзале даже если там вообще нет поездов. Вариант с селектором: ситуация та же, но для каждой платформы есть индикатор, сигнализирующий сотруднику вокзала (поток выполнения) о прибытии поезда. Таким образом на вокзале достаточно присутствия одного сотрудника.

Влияние Java NIO и Java IO на дизайн приложения

Выбор между Java NIO и Java IO может на следующие аспекты дизайна вашего приложения:
1. API обращений к классам ввода/вывода;
2. Обработка данных;
3. Количество потоков выполнения, использованных для обработки данных.

API обращений к классам ввода/вывода

Естественно, использование Java NIO серьезно отличается от использования Java IO. Так как, вместо чтения данных байт за байтом с использованием, например InputStream, данные для начала должны быть считаны в буфер и браться для обработки уже оттуда.

Обработка данных

Обработка данных при использовании Java NIO тоже отличается.
Как уже упоминалось, при использовании Java IO вы читаете данные байт за байтом с InputStream или Reader. Представьте, что вы проводите считывание строк текстовой информации:

Name: Anna
Age: 25
Email: anna@mailserver.com
Phone: 1234567890

Этот поток строк текста может обрабатываться следующим образом:

Обратите внимание, как состояние процесса обработки зависит от того, насколько далеко продвинулось выполнение программы. Когда первый метод readLine() возвращает результат выполнения, вы уверенны – целая строка текста была считана. Метод является блокирующим и действие блокировки продолжается до тех пор, пока вся строка не будет считана. Вы также четко понимаете, что данная строка содержит имя. Подобно этому, когда метод вызывается во второй раз, вы знаете, что в результате получите возраст.

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

Имплементация с использованием Java IO будет выглядеть несколько иначе:

Обратите внимание на вторую строчку кода, в которой происходит считывание байтов из канала в ByteBuffer. Когда возвращается результат выполнения данного метода, вы не можете быть уверенны, что все необходимые вам данные находятся внутри буфера. Все, что вам известно, так это то, что буфер содержит некоторые байты. Это немного усложняет процесс обработки.

Представьте, что после первого вызова метода read(buffer), в буфер было считано только половину строки. Например, “Name: An”. Сможете ли вы обработать такие данные? Наверное, что нет. Вам придется ждать пока, по крайней мере, одна полная строка текста не будет считана в буфер.

Так как же вам узнать, достаточно ли данных для корректной обработки содержит буфер? А никак. Единственный вариант узнать, это посмотреть на данные, содержащиеся внутри буфера. В результате вам придется по нескольку раз проверять данные в буфере, пока они не станут доступными для корректной обработки. Это неэффективно и может негативно сказаться на дизайне программы. Например:

Метод bufferFull() должен следить за тем, сколько данных считано в буфер и возвращать true или false, в зависимости от того, заполнен буфер или нет. Другими словами, если буфер готов к обработке, то он считается заполненным.

Также метод bufferFull() должен оставлять буфер в неизмененном состоянии, поскольку в противном случае следующая порция считанных данных может быть записана в неправильное место.

Если буфер заполнен, данные из него могут быть обработаны. Если он не заполнен вы все же будете иметь возможность обработать уже имеющиеся в нем данные, если это имеет смысл в вашем конкретном случае. В большинстве случаев – это бессмысленно.

Следующая схема демонстрирует процесс определения готовности данных в буфере для корректной обработки:

Итоги

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

Если вам необходимо управлять тысячами открытых соединений одновременно, причем каждое из них передает лишь незначительный объем данных, выбор Java NIO для вашего приложения может дать преимущество. Дизайн такого типа схематически изображен на следующем рисунке:

Если вы имеете меньшее количество соединений, по которым передаются большие объемы данных, то лучшим выбором станет классический дизайн системы ввода/вывода:

Важно понимать, что Java NIO отнюдь не является заменой Java IO. Его стоит рассматривать как усовершенствование – инструмент, позволяющий значительно расширить возможности по организации ввода/вывода. Грамотное использование мощи обоих подходов позволит вам строить хорошие высокопроизводительные системы.

Стоит заметить, что с выходом версии Java 1.7 появился еще и Java NIO.2, но присущие ему новшества касаются, в первую очередь, работы с файловым вводом/выводом, поэтому выходят за рамки этой статьи.

Java Nio Channels Example

Posted by: Yatin in nio October 9th, 2017 0 Views

Channels are the second major innovation of the Java Nio after buffers. In Java Nio, channels are used for the input-output transfers and this tutorial explains how the Java Nio Channels are used to open the network connections and connections to the files.

1. Introduction

Java Nio was developed to allow the Java programmers implement the high-speed I/O operations without using the custom native code. Nio moves the time-taking I/O activities like filling, namely and draining buffers etc back into the operating system, thus allows an increase in the operational speed.

Java Nio consists of the following core components:

    Channel & Buffers: In standard, I/O API the character streams and the byte streams are used but in NIO, developers work with the channels and buffers. In this case, the data is always written from a buffer to a channel and read from a channel to a buffer

Fig. 1: Channel & Buffers

Fig. 2: A Thread uses a Selector to handle 3 Channel’s

Do note, Java NIO has more components and >Channel , Buffer , and Selector are used as the core of the API.

1.1 Java Nio Components

The Java Nio classes are contained in the java.nio package and it is important to understand that the Nio subsystem does not replace the existing stream-based I/O classes available in java.io package. The important Nio classes are grouped under different categories that are shown below:

Fig. 3: Nio Components

Читать еще:  Java lang string

Let us understand the important classes contained in these groups.

PackagePurpose
java.nioIt is a top-level package for NIO system. The various types of buffers are encapsulated by this NIO system.
java.nio.charsetIt encapsulates the character sets and also supports the encoding and the decoding operation that converts the characters to bytes and bytes to characters.
java.nio.charset.spiIt supports the service provider for the character sets.
java.nio.channelsIt supports the channel which is essentially open for the I/O connections.
java.nio.channels.spiIt supports the service providers for the channels.
java.nio.fileIt provides the support for the files.
java.nio.file.spiIt supports the service providers for the file system.
java.nio.file.attributeIt provides the support for the file attributes.

1.2 Java Nio Channels

In Java Nio, Channels are used for the input-output transfers. A channel is a like a tube that transports the data between a buffer and an entity at the other end . A channel reads the data from an entity and places it in the buffer blocks for consumption. The developers then write the data to the buffer blocks so that it can be transported by the channel to the other end.

Channels are the gateway provided by the Java Nio package to access the native input-output mechanism. Developers should use buffers to interact with the channels and to perform the input-output operations where these buffers act as the endpoints provided by the channels to send and receive the data.

Fig. 4: Class hierarchy for Java Nio Channels

1.2.1 Channel Characteristics

  • Unlike streams, channels are two-way in nature and can perform both, read and write operations
  • A channel reads the data into a buffer and writes the data from a buffer
  • A channel can even perform the asynchronous read and write operations
  • A non-blocking channel does not put the invoking thread in the sleep mode
  • Stream-oriented channels like sockets can only be placed in the non-blocking mode
  • The data can be transferred from one channel to another if any one of the channels is a FileChannel

Fig. 5: NIO Channels

1.2.2 Channel Classes

Below are the two major types of channel classes provided as an implementation in the Java Nio package:

  • FileChannel : These are the File-based read/write channels that cannot be placed in a non-blocking mode
  • SocketChannel : The Java Nio Socket Channel is used for connecting a channel with a TCP network socket. It is equivalent to the Java Networking Sockets used in the network programming. There are two methods available in the Java Nio package for creating a SocketChannel i.e. ServerSocketChannel and the DatagramChannel . Do note, SocketChannel are the selectable channels that can easily operate in the non-blocking mode

Now, open up the Eclipse IDE and let’s see the basics of the Java Nio Channel.

2. Java Nio Channel Example

2.1 Tools Used

We are using Eclipse Kepler SR2, JDK 8 and Maven. Having said that, we have tested the code against JDK 1.7 and it works well.

2.2 Project Structure

Firstly, let’s review the final project structure, in case you are confused about where you should create the corresponding files or folder later!

2.3 Project Creation

This section will demonstrate on how to create a Java-based Maven project with Eclipse. In Eclipse IDE, go to File -> New -> Maven Project .

In the New Maven Project window, it will ask you to select project location. By default, ‘Use default workspace location’ will be selected. Select the ‘Create a simple project (skip archetype selection)’ checkbox and just click on next button to proceed.

It will ask you to ‘Enter the group and the artifact id for the project’. We will input the details as shown in the below image. The version number will be by default: 0.0.1-SNAPSHOT .

Click on Finish and the creation of a maven project is completed. If you observe, it has downloaded the maven dependencies and a pom.xml file will be created. It will have the following code:

Developers can start adding the dependencies that they want like JUnit etc. Let’s start building the application!

3. Application Building

Below are the steps involved in developing this application.

3.1 Java Class Creation

Let’s create the required Java files. Right-click on src/main/java folder, New -> Package .

A new pop window will open where we will enter the package name as: com.jcg.java.nio .

Once the package is created in the application, we will need to create the implementation class. Right-click on the newly created package: New -> Class .

A new pop window will open and enter the file name as: ChannelExample . The receiver class will be created inside the package: com.jcg.java.nio .

3.1.1 Implementation of Utility Class

Let’s see the example of copying the data from one channel to another channel (or from one file to another file). Add the following code to it:

4. Run the Application

To run the Java Nio application, Right-click on the ChannelExample class -> Run As -> Java Application . Developers can debug the example and see what happens after every step!

5. Project Demo

When developers run the above program, the input file’s data will be copied to the output’s file and the code shows the following status as output.

That’s all for this post. Happy Learning!!

6. Conclusion

This tutorial uses a simple example to illustrate the Channel’s functionality and helps developers understand the basic configuration required to achieve this operation. That’s all for this tutorial and I hope this article served you whatever you were looking for.

7. Download the Eclipse Project

This was an example of Java Nio for the beginners.

Файловые каналы

Содержание

Введение

Каналы являются новой возможностью библиотеки Java, частью нового пакета ввода/вывода (java.nio). В документации (http://java.sun.com/j2se/1.4/docs/api/java/nio/channels/Channel.html) каналы определяются следующим образом:

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

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

Предположим, что у вас имеются некоторые данные в бинарных файлах. Эти данные представляют собой несколько 16-ти битных чисел, записываемых следующей программой на языке С:

Эта программа записывает пять 16-ти битных значений в файл. Каждое значение записывается в виде двух байт, младший байт пишется первым (такой порядок следования байтов называется «little-endian» — прямым порядком). Откомпилируйте, скомпонуйте и выполните программу для создания файла данных.

Чтение данных из файла

Как можно прочитать эти данные в Java-программе? Вот один из способов:

public class ChannelDemo0 <
public static void main ( String args []) throws IOException <
FileInputStream fis = new FileInputStream ( «data» ) ;
DataInputStream dis = new DataInputStream ( fis ) ;
short s = dis.readShort () ;
System.out.println ( s ) ;
dis.close () ;
>
>

Читать еще:  Стандартные ошибки параметров регрессии

В этой программе используется класс DataInputStream и метод readShort этого класса. Однако если вы выполните программу ChannelDemo0, результат ее работы будет таким:

К сожалению, он не соответствует первоначальному значению (1234), записанному в файл данных. Проблема в том, что программа на языке С записывает значения типа short в порядке младший байт/старший байт, а метод readShort использует порядок — старший байт/младший байт.

Как решить эту проблему? Вот другой подход, в котором значения читаются из файла данных, и вычисляется их сумма:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;

public class ChannelDemo1 <

// просуммировать значения типа short из файла данных

static short sumFileContents ( String fn ) throws IOException <

// открыть поток ввода и создать канал

FileInputStream fis = new FileInputStream ( fn ) ;
FileChannel fc = fis.getChannel () ;

// отобразить файл в байтовый буфер

MappedByteBuffer mbb = fc.map ( FileChannel.MapMode.READ_ONLY, 0 , fc
.size ()) ;

// установить прямой порядок байтов

// создать ссылку на байтовый буфер как на буфер значений short

ShortBuffer sb = mbb.asShortBuffer () ;

short sum = 0 ;
while ( sb.hasRemaining ()) <
sum += sb.get () ;
>

public static void main ( String args []) throws IOException <
short sum = sumFileContents ( «data» ) ;
System.out.println ( sum ) ;
>
>

Метод sumFileContents сначала создает FileInputStream, а затем файловый канал, основанный на этом потоке. Аналогичный подход используется для потоков вывода (FileOutputStream) или для файлов, которые открыты и по чтению и по записи (RandomAccessFile).

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

Затем порядок байтов в байтовом буфере указывается как прямой (little-endian), в отличие от обратного порядка (big-endian) по умолчанию. Далее в методе создается «буфер просмотра» значений short на байтовом буфере. Буфер просмотра предоставляет доступ к отображенному байтовому буферу как к последовательности значений типа short (16-бит). Значения short состоят из двух байт, младший байт считается первым, для того чтобы соответствовать записанным программой на языке С значениям. Буфер просмотра основан на байтовом буфере. То есть, метод фактически создает представление файла данных как последовательности значений short в формате little-endian. Последнее действие метода — суммирование значений.

После выполнения программы ChannelDemo1 вы получите следующий результат:

Пример отображения файлов

Давайте продолжим и рассмотрим еще один пример отображения файлов. Предположим, что вы хотите поменять порядок байтов в файле. Как это можно сделать? Один из простых способов приведен ниже.

import java.nio.*;
import java.nio.channels.*;
import java.io.*;

public class ChannelDemo2 <
public static void main ( String args []) throws IOException <

// проверить аргументы командной строки

if ( args.length != 1 ) <
System.err.println ( «missing file argument» ) ;
System.exit ( 1 ) ;
>

RandomAccessFile raf = new RandomAccessFile ( args [ 0 ] , «rw» ) ;
FileChannel fc = raf.getChannel () ;

// отобразить файл в буфер

MappedByteBuffer mbb = fc.map ( FileChannel.MapMode.READ_WRITE, 0 , fc
.size ()) ;

// реверсировать байты в файле

int len = ( int ) fc.size () ;
for ( int i = 0 , j = len — 1 ; i ) <
byte b = mbb.get ( i ) ;
mbb.put ( i, mbb.get ( j )) ;
mbb.put ( j, b ) ;
>

Программа открывает канал, основанный на объекте RandomAccessFile, и отображает файл для чтения и записи. Затем выполняется цикл, который меняет байты, начиная с обоих концов буфера и заканчивая на его середине. Поскольку MappedByteBuffer отображен на дисковый файл, изменения в буфере отражаются в файле. Если вы выполните команды:

и посмотрите на текст в ChannelDemo2.java, вы обнаружите, что все байты в ChannelDemo2.java расположены в обратном порядке. Другими словами, первой строкой в файле должна быть:

Для восстановления файла ChannelDemo2.java в оригинальный вид вы должны выполнить команду:

Копирование содержимого с использованием файловых каналов

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

Рассмотрим несколько способов копирования одного файла в другой с использованием возможностей файловых каналов. Первый подход является еще одним примером отображенных файлов:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;

public class ChannelDemo3 <
public static void main ( String args []) throws IOException <

// проверить аргументы командной строки

if ( args.length != 2 ) <
System.err.println ( «missing filenames» ) ;
System.exit ( 1 ) ;
>

FileInputStream fis = new FileInputStream ( args [ 0 ]) ;
FileOutputStream fos = new FileOutputStream ( args [ 1 ]) ;
FileChannel fcin = fis.getChannel () ;
FileChannel fcout = fos.getChannel () ;

// отобразить входной файл

MappedByteBuffer mbb = fcin.map ( FileChannel.MapMode.READ_ONLY, 0 , fcin
.size ()) ;

// выполнить копирование файла

fcin.close () ;
fcout.close () ;
fis.close () ;
fos.close () ;
>
>

В этом примере входной файловый канал отображается в буфер, а затем этот буфер записывается в выходной канал. Поскольку буфер представляет целый файл, запись в буфер эквивалентна копированию файла. Поэтому, если вы выполните команды:

файл ChannelDemo3 скопируется в ChannelCopy3.java.

Копирование с помощью метода transferTo

Другой способ копирования файла выглядит следующим образом:

import java.nio.*;
import java.nio.channels.*;
import java.io.*;

public class ChannelDemo4 <
public static void main ( String args []) throws IOException <

// проверить аргументы командной строки

if ( args.length != 2 ) <
System.err.println ( «missing filenames» ) ;
System.exit ( 1 ) ;
>

FileInputStream fis = new FileInputStream ( args [ 0 ]) ;
FileOutputStream fos = new FileOutputStream ( args [ 1 ]) ;
FileChannel fcin = fis.getChannel () ;
FileChannel fcout = fos.getChannel () ;

// выполнить копирование файла

fcin.transferTo ( 0 , fcin.size () , fcout ) ;

fcin.close () ;
fcout.close () ;
fis.close () ;
fos.close () ;
>
>

Метод transferTo передает байты из канала-источника (fcin) в указанный канал-назначение (fcout). Передача обычно производится без явных чтений или записи в канал на уровне пользователя. В документации (http://java.sun.com/j2se/1.4/docs/api/java/nio/channels/FileChannel.html#transferTo(long, long, java.nio.channels.WritableByteChannel)) по поводу метода transferTo говорится:

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

Другими словами, метод transferTo должен полагаться на специальные возможности операционной системы, поддерживающей очень быструю передачу файлов.

Как выглядит «обычное» копирование файла с использованием каналов? Вот пример:

import java.io.*;
import java.nio.*;
import java.nio.channels.*;

public class ChannelDemo5 <
public static void main ( String args []) throws IOException <

// проверить аргументы командной строки

if ( args.length != 2 ) <
System.err.println ( «missing filenames» ) ;
System.exit ( 1 ) ;
>

FileInputStream fis = new FileInputStream ( args [ 0 ]) ;
FileOutputStream fos = new FileOutputStream ( args [ 1 ]) ;
FileChannel fcin = fis.getChannel () ;
FileChannel fcout = fos.getChannel () ;

ByteBuffer buf = ByteBuffer.allocateDirect ( 8192 ) ;

long size = fcin.size () ;
long n = 0 ;
while ( n ) <
buf.clear () ;
if ( fcin.read ( buf ) 0 ) <
break ;
>
buf.flip () ;
n += fcout.write ( buf ) ;
>

fcin.close () ;
fcout.close () ;
fis.close () ;
fos.close () ;
>
>

Эта программа копирует один файл в другой, один буфер за раз. Перед чтением каждой части входного файла в буфер программа «очищает» буфер. Это подготавливает буфер к чтению, позиция устанавливается в 0, а граница — в размер буфера. Затем, после каждого чтения, программа «перебрасывает» буфер. Это подготавливает буфер для записи, граница устанавливается в текущую позицию, а текущая позиция — в 0.

Ссылка на основную публикацию
Adblock
detector