1.使用nio读写文件
public class NioTest {
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream("input.txt");
FileOutputStream outputStream = new FileOutputStream("output.txt");
FileChannel inputChannel = inputStream.getChannel();
FileChannel outputChannel = outputStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(512);
int read;
while ((read = inputChannel.read(buffer)) != -1) {
System.out.println("read: " + read);
buffer.flip();
outputChannel.write(buffer);
buffer.clear();//注释掉该行代码会发生什么呢?
}
inputChannel.close();
outputChannel.close();
}
}
控制台:
read: 22
当我们注释掉 buffer.clear() 后,发现会无限循环下去,并且也会将input.txt
中的内容无限写入output.txt
read: 22
read: 0
read: 0
read: 0
read: 0
...
原因是什么呢?
当我们注释掉clear()后,
在第一次向buffer写入数据后,然后又读取完毕后,pos是等于lim的;
当再向buffer种写入数据后,因为pos == lim;会无法写入,就会返回0,而不是-1;
只有在file-position走到末尾的时候,才返回-1,否则返回的都是在buffer里面写入了多少个元素;
因为pos == lim; 所以一个都写不进去,所以返回0。
然后调用flip(),pos=0,所以又会重写读buffer中数据,写入到output.txt。
参考自ReadableByteChannel
接口的read()
文档
/*
* @return The number of bytes read, possibly zero, or <tt>-1</tt> if the
* channel has reached end-of-stream
/
2.MappedByteBuffer
/**
* MappedByteBuffer作用:可以让文件直接在内存(堆外的内存)中进行修改,而操作系统不需要拷贝一次,
* 有点像 DirectByteBuffer
* 实际上DirectByteBuffer也是MappedByteBuffer作用的子类。
*
* 注意:执行完代码后,IDEA的文件并没有及时改变,但是如果我们在外面打开文件,他的确是发生改变的。
*/
public static void main(String[] args) throws IOException {
RandomAccessFile file = new RandomAccessFile("NioTest.txt", "rw");
FileChannel channel = file.getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, 5);
map.put(0, (byte)'a');
map.put(3, (byte)'b');
file.close();
}
NioTest.txt文件就由
hello world java
变成了
aelbo world java
虽然在idea中没有变化,但是用notepad++打开查看后,其实已经发生了变化。
3.文件锁
public class NioTest4 {
public static void main(String[] args) throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("1.txt", "rw");
FileChannel fileChannel = randomAccessFile.getChannel();
FileLock lock = fileChannel.lock(3, 6, true);
System.out.println("valid: " + lock.isValid());
System.out.println("lock type: " + lock.isShared());
lock.release();
randomAccessFile.close();
}
}
控制台:
valid: true
lock type: true
4.Scattering与Gathering
/*
Scattering:将数据从一个Channel依次读取到多个Buffer中
Gathering:依次将多个Buffer中的数据写入到一个Channel中
*/
public class NioTest3 {
public static void main(String[] args) throws Exception {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
InetSocketAddress address = new InetSocketAddress(8899);
serverSocketChannel.socket().bind(address);
int messageLength = 2 + 3 + 4;
ByteBuffer[] buffers = new ByteBuffer[3];
buffers[0] = ByteBuffer.allocate(2);
buffers[1] = ByteBuffer.allocate(3);
buffers[2] = ByteBuffer.allocate(4);
SocketChannel socketChannel = serverSocketChannel.accept();
while (true) {
int bytesRead = 0;
while (bytesRead < messageLength) {
long r = socketChannel.read(buffers);
bytesRead += r;
System.out.println("bytesRead: " + bytesRead);
Arrays.stream(buffers).
map(buffer -> "position: " + buffer.position() + ", limit: " + buffer.limit()).
forEach(System.out::println);
}
Arrays.asList(buffers).forEach(Buffer::flip);
long bytesWritten = 0;
while (bytesWritten < messageLength) {
long r = socketChannel.write(buffers);
bytesWritten += r;
}
Arrays.asList(buffers).forEach(Buffer::clear);
System.out.println("bytesRead: " + bytesRead + ", bytesWritten: " + bytesWritten + ", messageLength: " + messageLength);
}
}
}
客户端用 输入以下命令,建立连接
telnet localhost 8899