1.NIO
在Java的标准I/O中,提供了基于流的I/O实现,即InputStream
和OutputStream
。NIO是New I/O的是简称,基于块(Block),以块为基本单位处理数据。其中最主要的两个概念是缓冲(Buffer
)和通道(Channel
)。
NIO实现文件的拷贝,读取Channel
中的数据,写入Buffer
中,再从Buffer
中读取。
public void copyFile(String fileInput, String fileOutput) {
try {
FileInputStream input = new FileInputStream(fileInput);
FileOutputStream output = new FileOutputStream(fileOutput);
FileChannel inputChannel = input.getChannel();
FileChannel outputChannel = output.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(inputChannel.read(buffer) != -1) {
buffer.flip();
outputChannel.write(buffer);
buffer.clear();
}
input.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
2.缓冲Buffer
Buffer
有三个重要参数
- 位置(
position
),从position
开始读写 - 容量(
capacity
),缓冲区的总容量上限。 - 限制(
limit
),缓冲区数据上限。
Buffer创建
Buffer
通过allocate(int)
或wrap()
方法创建,初始化后,position
为0
,而capacity
和limit
都为最大
ByteBuffer buffer = ByteBuffer.allocate(15);
BufferTool.printBuffer(buffer);
byte[] byteArray = new byte[10];
buffer = ByteBuffer.wrap(byteArray);
BufferTool.printBuffer(buffer);
输出
position = 0, capacity = 15, limit = 15
position = 0, capacity = 10, limit = 10
BufferTool.java文件
public static void printBuffer(Buffer buffer) {
System.out.println("position = " + buffer.position()
+ ", capacity = " + buffer.capacity()
+ ", limit = " + buffer.limit());
}
Buffer读写
get()
,返回当前position
上的数据,并将position
向后移一位。get(byte[] dst)
,读取当前数据到dst
中,并移动position
位置。get(int index)
,读取指定索引上的数据,不改变position
位置。put(byte)
,当前位置写入给定数据,position
向后移一位。put(byte[] src)
,写入给定数据,并移动position
位置。put(int index, byte b)
,指定索引写入给定数据,不改变position
位置。
在下面示例中,我们首先调用put()
方法添加,然后调用flip()
进行读写转换,最后使用get()
方法读取数据。
ByteBuffer buffer = ByteBuffer.allocate(15);
buffer.put((byte)0);
buffer.put((byte)1);
byte[] src = new byte[] {2, 3, 4};
buffer.put(src);
BufferTool.printBuffer(buffer);
buffer.flip();
System.out.println("after flip");
BufferTool.printBuffer(buffer);
System.out.println("get = " + buffer.get());
BufferTool.printBuffer(buffer);
byte[] dst = new byte[2];
buffer.get(dst);
System.out.println(dst[0] + ":" + dst[1]);
BufferTool.printBuffer(buffer);
输出
position = 5, capacity = 15, limit = 15
after flip
position = 0, capacity = 15, limit = 5
get = 0
position = 1, capacity = 15, limit = 5
1:2
position = 3, capacity = 15, limit = 5
修改Buffer状态
rewind()
,将position
清空。clear()
,也将position
清空,同时将limit
设置为capacity
的大小。flip()
,实现读写转换,同时设置limit
为position
。mark()
,用来记录当前位置。reset()
,用来恢复到mark
所在的位置。
具体实现
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
public final Buffer mark() {
mark = position;
return this;
}
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
3. ByteBuffer
-
duplicate()
,以缓冲区为基础,生成一个完全一样的新缓冲区。新缓冲区与原缓冲区共享相同的内存数据,又独立维护各自的position
、limit
和mask
。 -
slice()
,在现有的缓冲区中,创建新的子缓冲区,子缓冲区与父缓冲区共享内存数据。ByteBuffer buffer = ByteBuffer.allocate(15); for (int index = 0; index < 10; index++) { buffer.put((byte) index); } buffer.flip(); BufferTool.printByteBuffer(buffer); ByteBuffer duplicateBuffer = buffer.duplicate(); duplicateBuffer.put(0, (byte) 10); BufferTool.printByteBuffer(buffer); buffer.position(3); buffer.limit(6); ByteBuffer sliceBuffer = buffer.slice(); BufferTool.printByteBuffer(sliceBuffer); sliceBuffer.put(0, (byte) 30); buffer.limit(10); BufferTool.printByteBuffer(buffer);
输出
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [10, 1, 2, 3, 4, 5, 6, 7, 8, 9] [3, 4, 5] [10, 1, 2, 30, 4, 5, 6, 7, 8, 9]
BufferTool.java文件
public static void printByteBuffer(ByteBuffer buffer) { System.out.print("["); for (int index = 0; index < buffer.limit(); index++) { if (index != 0) { System.out.print(", "); } System.out.print(buffer.get(index)); } System.out.println("]"); }
-
asReadOnlyBuffer()
,生成只读缓存区,可以保证数据不被修改。 -
allocateDirect(int capacity)
,直接访问物理内存。