第一次接触,所以先从定义开始吧
java.nio 全程是java non-blocking IO,非阻塞型IO。根据这个段时间的学习,知道,java.IO是同步阻塞型的,每一次调用writer和read的时候,都会加锁,意味如果很多用户的话,必须排队
NIO主要有三大核心部分:Channel,Buffer,Selector。传统IO基于字节流和字符流进行操作,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作。数据总是由通道读取到缓冲区,或者从缓冲区写入到通道。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此单线程可以监听多个数据通道。
NIO和传统IO的第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。
IO的各种流是阻塞的。这意味着,当一个线程调用read或write时,该线程被阻塞,直到有一些 数据被读取,或数据完全写入。该线程在此期间不能干任何事情。NIO是非阻塞模式,使一个线程从某通道发送请求读取数据,但它只能得到目前可用的数据。如果目前没有数据可用时,就什么也不会获取。而不是保持线程阻塞,所以直到数据变的可读取之前,该线程可以继续做其他的事情,非阻塞的写也是如此。线程通常将非阻塞IO空闲时间用在其他通道上执行IO操作,所以一个单独的线程在现在可以管理多个输入和输出通道(channel)。
channel,不像流,流是单向的,channel是双向的,既可以用来读,也可以用来写。
//通道表示一个实体的(硬件设备,文件,网络套接字,一个程序组件)的开放性连接,执行一个多或多个IO操作。读或写。。。
//通道要么打开,要么关闭,通道在创建的时候打开,关闭的时候关闭。
//一旦关闭。任何关于IO的操作都会抛异常
//多线程访问安全
public interface Channel extends Closeable{
//判断通道是否打开
public boolean isOpen();
//关闭通道
public void close() throws IOException;
}
buffer,buffer用于和channel进行交互,数据是从通道进入缓冲区,从缓冲区写入到通道中的 。
实际上是一个容器,连续数组,Channel提供从文件、网络读取数据的渠道,但是读写的数据都必须经过Buffer
一个buffer的capacity是buffer包含元素的数量,buffer的capacity是不为负且不会改变
buffer的limit是第一个不被读或写的元素的指标,buffer的limit不为负且不能超过buffer的capacity
buffer的position是下一个将要被读或写的元素的指标,buffer的position不为负且不能超过buffer的limit
private int mark = -1; //用于记录当前position的前一个位置或者默认是-1
private int position = 0;
private int limit;
private int capacity;
Buffer(int mark, int pos, int lim, int cap) { // package-private
if (cap < 0)
throw new IllegalArgumentException("Negative capacity: " + cap);
this.capacity = cap;
limit(lim);
position(pos);
if (mark >= 0) {
if (mark > pos)
throw new IllegalArgumentException("mark > position: ("
+ mark + " > " + pos + ")");
this.mark = mark;
}
}
public final Buffer limit(int newLimit) {
if ((newLimit > capacity) || (newLimit < 0))
throw new IllegalArgumentException();
limit = newLimit;
if (position > limit) position = limit;
if (mark > limit) mark = -1;
return this;
}
public final Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
if (mark > position) mark = -1;
return this;
}
向Buffer中写的数据
从Channel中写入。。。
selector:selector运行单线程处理多个Channel。
关于FileChannel
// 是一个读取,写入,映射,和操作文件的通道
// java.io.FileInputStream#getChannel()
// java.io.FileOutputStream#getChannel()
// java.io.RandomAccessFile#getChannel()
public abstract class FileChannel
extends AbstractInterruptibleChannel
implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
//初始化一个新的实例
protected FileChannel() { }
//打开或创建一个文件,返回访问文件的通道
//path 文件的路径
//options 文件打开的方式
//attrs 可选的文件属性列表
public static FileChannel open(Path path,
Set<? extends OpenOption> options,
FileAttribute<?>... attrs)
throws IOException
{
FileSystemProvider provider = path.getFileSystem().provider();
return provider.newFileChannel(path, options, attrs);
}
//从通道中读取一个字节序列到ByteBuffer中
/每写读次,ByteBuffer 中的positon都会更新,大小为positon + n
//其中 n = ByteBuffer.limit,若最后一次,就是最后一次读取的byte的数目
public abstract int read(ByteBuffer dst) throws IOException;
//从通道中读取字节序列到指定的ByteBuffer数组
public abstract long read(ByteBuffer[] dsts, int offset, int length)
throws IOException;
public final long read(ByteBuffer[] dsts) throws IOException {
return read(dsts, 0, dsts.length);
}
//Bytes 从该通道的当前文件位置开始读取字节,然后使用实际读取的字节数更新文件位置。
//从给定的buffer中,向通道中写一序列字节
//每写一次,ByteBuffer 中的positon都会更新,大小为positon + n
//其中 n = ByteBuffer.limit,若最后一次,就是最后一次读取的byte的数目
public abstract int write(ByteBuffer src) throws IOException;
//从给定的buffer[]中,从offset开始,读取length字节,向通道中写入
public abstract long write(ByteBuffer[] srcs, int offset, int length)
throws IOException;
public final long write(ByteBuffer[] srcs) throws IOException {
return write(srcs, 0, srcs.length);
}
//返回通道中文件的位置
public abstract long position() throws IOException;
//设置通道中文件的位置
public abstract FileChannel position(long newPosition) throws IOException;
//返回当前通道中文件的大小(实时)
public abstract long size() throws IOException;
//将此通道的文件截取为指定大小
public abstract FileChannel truncate(long size) throws IOException;
//将字节从此通道的文件传输到给定的可写字节通道。
public abstract long transferTo(long position, long count,
WritableByteChannel target)
throws IOException;
。。。。。。。。。。。。。
public class JavaNio {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream("E:\\sourcecode\\hello.txt");
FileChannel inChannel = ((FileInputStream) in).getChannel();
OutputStream out = new FileOutputStream("E:\\sourcecode\\hello1.txt");
FileChannel outChannel = ((FileOutputStream) out).getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(2);
while((inChannel.read(byteBuffer))!=-1){
byteBuffer.flip();
if(byteBuffer.hasRemaining()){
outChannel.write(byteBuffer);
}
byteBuffer.compact();
}
out.close();
in.close();
}
}
//分配一个新的字节缓冲区。
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
HeapByteBuffer(int cap, int lim) { // package-private
super(-1, 0, lim, cap, new byte[cap], 0);
}
/***************************************************
buf.clear(); // Prepare buffer for use
while (in.read(buf) >= 0 || buf.position != 0) {
buf.flip();
out.write(buf);
buf.compact(); // In case of partial write
}
***************************************************/
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
public final boolean hasRemaining() {
return position < limit;
}