В прошлом я говорил о RandomAccessFile и о том, как его можно использовать для ускорения ввода-вывода в Java, а в этом руководстве по Java NIO мы увидим, как использовать данные для чтения / записи при использовании FileChannel и ByteBuffer .
Канал предоставляет альтернативный способ чтения данных из файла, он обеспечивает лучшую производительность, чем InputStream или OutputStream. Его также можно открыть в режиме блокировки и неблокирования. Хотя FileChannles являются каналами чтения / записи, и они всегда блокируют , их нельзя перевести в неблокирующий режим. Класс RandomAccessFile обрабатывает файл как массив байтов.
Вы можете записать свои данные в любую позицию массива, и вы можете читать из любой позиции. Для этого он использует указатель, который содержит текущую позицию и предоставляет несколько методов, таких как seek() для перемещения этого указателя. Как только вы окажетесь в правильном положении, вы можете получить FileChannel из RandomAccessFile и начать чтение данных из файла. Кстати, JDK 7 также представил NIO 2, что делает работу с файлами и каталогами еще проще. Прочитайте про Java 7 NIO.2 Ангела Леонарда, чтобы узнать больше о.
Как читать / записывать файлы, используя FileChannel и ByteBuffer
Прежде чем приступить к написанию кода, давайте пересмотрим базовую концепцию Channel и Buffer в Java NIO. Одним словом, буферы работают с каналом. Каналы — это труба, по которой передаются данные, а буферы являются источником и целью этой передачи данных. В случае записи данные, которые вы хотите записать, помещаются в буфер, который передается в канал, а затем канал считывает эти данные из буфера и записывает в файл.
Точно так же в случае чтения канал помещает данные в буфер, который вы предоставляете из файла , сети или любого другого источника. Поскольку один и тот же буфер используется для чтения и записи, т.е. вы записываете данные в буфер, но канал считывает их для записи в файл, вы должны вызвать метод flip () после завершения записи в буфер. Метод flip () изменяет указатели и позволяет читать данные из буфера. В Java существует три типа буфера: прямой, непрямой и сопоставленный буфер . В этом примере мы будем использовать прямой байтовый буфер.
Шаги для чтения / записи данных с использованием FileChannel и Buffer
Вот пошаговое руководство по началу чтения данных из файла с использованием RandomAccessFile , FileChannel и ByteBuffer :
- Откройте файл, который вы хотите прочитать / записать, используя RandomAccessFile в режиме чтения / записи.
- Вызовите метод
getChannel()для RandomAccessFile, чтобы получить FileChannel. Положение возвращаемого канала всегда будет равно смещению указателя файла этого объекта, как возвращено методомgetFilePointer(). - Создайте ByteBuffer с помощью
ByteBuffer.allocate(). - Сохраните данные в ByteBuffer, используя различные методы
putInt(), например,putInt(),putLong(). - Переверните буфер, чтобы канал мог читать данные из буфера и записывать в файл. Метод flip () изменяет указатели и позволяет читать данные из буфера.
- Вызовите метод write () FileChannel.
- Закройте FileChannel
- Закройте файл RandomAccessFile.
Еще один важный момент, на который следует обратить внимание, это то, что вы можете использовать один и тот же буфер для чтения и записи, но его нужно перевернуть Теперь давайте рассмотрим пример Java-программы для чтения / записи данных из файлов, используя FileChannel и ByteBuffer в Java. После Memory Mapped File это второй самый быстрый способ чтения и записи из файла в Java.
Java программа для чтения / записи из файла с использованием FileChannel и ByteBuffer
Вот пример программы, чтобы продемонстрировать, как вы можете читать и записывать данные из файла (может быть двоичного или текстового файла) с использованием классов FileChannel и ByteBuffer. Я также использовал абстракцию для создания интерфейса под названием Persistable, который предоставляет два метода persist() и recover() . Любой объект, который реализует этот интерфейс, может быть сохранен и загружен, но как вы сохраняете и загружаете их, оставлено на усмотрение разработчика, т.е. вы можете использовать Chanel и Buffer, как мы это делали, или вы можете использовать старый подход для чтения / записи файла в Java ,
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
import java.io.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;/** * Java Program to read and write on RandomAccessFile in Java * using FileChannle and ByteBuffer. * * @author Javin */public class FileChannelDemo { public static void main(String args[]) { Tablet ipad = new Tablet("Apple", true, 1000); System.out.println("Writing into RandomAcessFile : " + ipad); write("tablet.store", ipad); Tablet fromStore = new Tablet(); read("tablet.store", fromStore); System.out.println("Object read from RandomAcessFile : " + fromStore); } /* * Method to write data into File using FileChannel and ByteBuffeer */ public static void write(String filename, Persistable object) { try { // Creating RandomAccessFile for writing RandomAccessFile store = new RandomAccessFile("tablet", "rw"); // getting FileChannel from file FileChannel channel = store.getChannel(); // creating and initializing ByteBuffer for reading/writing data ByteBuffer buffer = ByteBuffer.allocate(2048); // an instance of Persistable writing into ByteBuffer object.persist(buffer); // flip the buffer for writing into file buffer.flip(); int numOfBytesWritten = channel.write(buffer); // writing into File System.out.println("number of bytes written : " + numOfBytesWritten); channel.close(); // closing file channel store.close(); // closing RandomAccess file } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /* * Method to read data from File using FileChannel and ByteBuffeer */ public static void read(String filename, Persistable object) { try { // Opening RandomAccessFile for reading data RandomAccessFile store = new RandomAccessFile("tablet", "rw"); // getting file channel FileChannel channel = store.getChannel(); // preparing buffer to read data from file ByteBuffer buffer = ByteBuffer.allocate(1024); // reading data from file channel into buffer int numOfBytesRead = channel.read(buffer); System.out.println("number of bytes read : " + numOfBytesRead); // You need to filp the byte buffer before reading buffer.flip(); // Recovering object object.recover(buffer); channel.close(); store.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }} |
Наш интерфейс для абстрактного механизма чтения и записи. Это также фактическое использование интерфейса для обеспечения абстракции, отделяющей то, что нужно сделать, от того, как это сделать. Подобно этому интерфейсу, просто скажите «сохранитесь и восстановитесь», а не как вы это делаете.
|
1
2
3
4
5
6
|
interface Persistable { public void persist(ByteBuffer buffer); public void recover(ByteBuffer buffer);} |
Конкретный класс для реализации Persistable, чтобы сделать их читаемыми и записываемыми:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
class Tablet implements Persistable { private String brand; private boolean isCellular; private long cost; // in US Dollars public Tablet() { brand = ""; } public Tablet(String brand, boolean isCellular, long cost) { this.brand = brand; this.isCellular = isCellular; this.cost = cost; } public final String getBrand() { return brand; } public final boolean isCellular() { return isCellular; } public final long getCost() { return cost; } public final void setBrand(String brand) { this.brand = brand; } public final void setCellular(boolean isCellular) { this.isCellular = isCellular; } public final void setCost(long cost) { this.cost = cost; } @Override public void persist(ByteBuffer buffer) { byte[] strBytes = brand.getBytes(); buffer.putInt(strBytes.length); buffer.put(strBytes, 0, strBytes.length); buffer.put(isCellular == true ? (byte) 1 : (byte) 0); buffer.putLong(cost); } @Override public void recover(ByteBuffer buffer) { int size = buffer.getInt(); byte[] rawBytes = new byte[size]; buffer.get(rawBytes, 0, size); this.brand = new String(rawBytes); this.isCellular = buffer.get() == 1 ? true : false; this.cost = buffer.getLong(); } @Override public String toString() { return "Tablet [brand=" + brand + ", isCellular=" + isCellular + ", cost=" + cost + "]"; }} Output:Writing into RandomAcessFile : Tablet [brand=Apple, isCellular=true, cost=1000]number of bytes written : 18number of bytes read : 1024Object read from RandomAcessFile : Tablet [brand=Apple, isCellular=true, cost=1000] |
предосторожность
Не забудьте перевернуть байтовый буфер после записи в него содержимого объекта, потому что файловый канал должен прочитать его, чтобы записать данные в RandomAccessFile. Если вы забудете вызвать метод flip () перед вызовом FileChannel.write (), то в итоге вы ничего не напишите в файл.
Аналогично, после считывания данных из файла в буфер снова переверните его, чтобы вы могли прочитать данные из буфера в популярное содержимое объекта. Многие Java-программисты делают эту ошибку, не переворачивая после записи и заканчивая часами отладки, потому что либо ничего не записывается в файл, либо ничего не может прочитать из файла.
Это все о том, как читать / записывать файл, используя FileChannel и ByteBuffer в Java . В этом демоне я показал вам, как читать и писать файл RandomAccessFile, используя FileChannel и ByteBuffer, но вы можете применить ту же технику для чтения любого другого текстового или двоичного файла из программы Java.
| Ссылка: | Чтение / запись в / из файлов с использованием FileChannel и ByteBuffer на Java от нашего партнера по JCG Джавина Пола из блога Javarevisited . |
