NIO流(new io流)

Nio介绍

IO操作模式
PIO(programming IO):所有的io操作由CPU处理,CPU占用率比较高
DMA(Direct Memory Access) : (直接内存存取,直接存储器访问)CPU把IO操作控制权交给了DMA控制器,只能以固定的方式读写,CPU空闲做其他操作。
通道方式(Channel):能执行有限通道的控制器,代替CPU控制管理外设,通道有自己的指令系统,是一个协处理器,具有更强的独立处理数据输入和输出的能力。
IO与NIO区别
同步和异步都是基于应用程序和操作系统。
同步:应用程序直接参与IO读写,所以是阻塞的,需要等待IO完成。
异步:IO读写交给操作系统。非阻塞。
NIO(同步非阻塞):面向缓冲区,
IO:面向流,(阻塞的 浪费性能)
NIO:主要是通过selector选择器管理所有的IO事件,
服务端为例:首先需要serverSoketChannel.open();获得一个channel然后通过channel.configureBlocking(false);设置非阻塞再通过channel.socket();获取一个Serversocket,然后通过bing()绑定端口,后打开选择器 selector.open();通过channel.register(selector,key);注册通道。后通过selector.select();监听key.IO流:字节流是读到一个就返回一个,几乎所有文件都可以读取,字符流是只能读取字符,读文本优先用字符流。

Nio核心
Bufferd:缓冲区
Channel:通道
Selector:选择器(轮询器)
NIO与普通io流的区别:
io流 : NIO:
面向流 面向缓冲流(Buffer Oriented)
阻塞io 非阻塞IO(Non Blocking IO)
选择器(Selectors)

Buffer缓冲区
java NIO中的Buffer用于和NIO通道进行交互。数据从通道读入缓冲区,从缓冲区写入到通道中。
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存,这块内存被包裹成NIO Buffer对象,并提供一组方法,用来访问该内存。
java中关键的Buffer实现:ByteBuffer CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer

Buffer的 核心属性
mark
position 当前读写的位置
limit 可读写的最大位置, flip()之后 limit()可用于表示缓冲区数据长度
capacity 缓冲区的容量

Position
缓冲区实际上就是美化了的数组。在从通道读取时,您将所读取的数据放到底层的数组中。 position 变量跟踪已经写了多少数据。更准确地说,它指定了下一个字节将放到数组的哪一个元素中。因此,如果您从通道中读三个字节到缓冲区中,那么缓冲区的 position 将会设置为3,指向数组中第四个元素。
同样,在写入通道时,您是从缓冲区中获取数据。 position 值跟踪从缓冲区中获取了多少数据。更准确地说,它指定下一个字节来自数组的哪一个元素。因此如果从缓冲区写了5个字节到通道中,那么缓冲区的 position 将被设置为5,指向数组的第六个元素。
Limit
limit 变量表明还有多少数据需要取出(在从缓冲区写入通道时),或者还有多少空间可以放入数据(在从通道读入缓冲区时)。
position 总是小于或者等于 limit。
Capacity
缓冲区的 capacity 表明可以储存在缓冲区中的最大数据容量。实际上,它指定了底层数组的大小 ― 或者至少是指定了准许我们使用的底层数组的容量。
limit 不能大于 capacity

使用Buffer
1.创建缓冲区,写入数据到Buffer
2.调用filp(),翻转,用于切换模式
3.从Buffer中读取数据
4.调用clear() 或者compact()

代码实现

public static void main(String[] args) {
		//创建字节缓冲区对象,大小为1024
		ByteBuffer bb = ByteBuffer.allocate(1024);
		//往缓冲区中写入数据  
		bb.put("今天天气真不错!".getBytes());
		
		bb.flip();//翻转  用于切换模式
		
		//读数据
		byte[]  b= new byte[bb.limit()];//limit()  缓冲区的数据长度
		bb.get(b);//将冲区的数据获取到b数组中
		//打印数据
		System.out.println(new String(b,0,b.length));
		bb.clear();//将缓冲区清空
	}

创建FileChannel的两种方式
1.InputStream、OutputStream 或者RandomAccessFile
2.FileChannel.open()
(3种)

使用FileChannel 文件复制的的代码

1.InputStream OutputStream 方式

public static void main(String[] args) throws Exception {
		
		//管道
			FileInputStream   fis = new FileInputStream("H:/图片/001.jpg");
			FileOutputStream   fos = new FileOutputStream("H:/图片/0001.jpg");
			//通道
			FileChannel  fc=fis.getChannel();
			FileChannel  fo=fos.getChannel();
			//创建缓冲区
			ByteBuffer  bb = ByteBuffer.allocate(1024);
			while(fc.read(bb)!=-1) {//从源文件读数据写入到缓冲区
				bb.flip();//切换到读状态
				fo.write(bb);//从缓冲区读数据写入到目的地文件
				bb.clear();//清空缓冲区
			}
		
			fo.close();
			fc.close();
			fos.close();
			fis.close();
}

2.FileChannel

public static void main(String[] args) throws Exception {
		//通过FileChannel.open()方式复制          参数 (2个)   paths.get(),   StandardOpenOption.read
		FileChannel  fc=FileChannel.open(Paths.get("H:/图片/001.jpg"),StandardOpenOption.READ );
							//读取3个参数    paths.get()   StandarOpenOption.READ 读取       CREATE 创建
		FileChannel fc1=FileChannel.open(Paths.get("H:/图片/0002.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
		//创建缓冲区            ByteBuffer.allocate(100)非
		ByteBuffer bb=ByteBuffer.allocate(100);
		
		while(fc.read(bb)!=-1){
			bb.flip();//翻转
			fc1.write(bb);
			
			bb.clear();//清空
		}
	}

3.RandomAccessFile 适用于大文件读写

//读通道
		FileChannel  fc=new RandomAccessFile("E:/日志.txt", "r").getChannel();
		//写通道
		FileChannel  fo=new RandomAccessFile("D:/徐淼的同桌的同桌.txt", "rw").getChannel();
		//直接缓冲区
		MappedByteBuffer map = fc.map(MapMode.READ_ONLY, 0, fc.size());
		//因为map中直接有读取文件的所有数据,所以直接写就完事了!
		fo.write(map);

NIO网络编程(TCP)
客户端client

/*
	 * 1.创建客户端 /2.创建通道
	 * 3.缓冲区
	 * 4....
	 */
	
	public static void main(String[] args) throws Exception {
		
		Thread.currentThread().sleep(6000);
		//创建客户端通道
		SocketChannel sc = SocketChannel.open(new InetSocketAddress("10.9.151.86",5555));  
		ByteBuffer  bb=ByteBuffer.allocate(1024);//缓冲区
		bb.put("你好,服务器!".getBytes());//缓冲区写入数据
		bb.flip();//切换为读状态
		sc.write(bb);//写到服务器中
	
		sc.close();//关闭资源
	}

服务器端Server

public static void main(String[] args) throws Exception {
		/*
		 * 服务器:
		 */
		ServerSocketChannel  ssc = ServerSocketChannel.open();
		ssc.bind(new InetSocketAddress(5555));//绑定IP地址和端口号或者直接绑定端口号
		SocketChannel accept = ssc.accept();//阻塞状态:等待客户端连接
		
		ByteBuffer  bb = ByteBuffer.allocate(1024);//缓冲区
		accept.read(bb);//将客户端发送来的数据写入到缓冲区中
		
		bb.flip();//切换读模式
		byte[]  b = new byte[bb.limit()];//可读数据的最大个数
		bb.get(b);//将缓冲区中的数据读取到b数组中
		
		System.out.println(accept.getLocalAddress()+":"+new String(b,0,b.length));//将客户端发送来的数据打印
		ssc.close();//关闭资源
			
	}

猜你喜欢

转载自blog.csdn.net/qq_42435514/article/details/82888895
今日推荐