NIO编程

什么是NIO?

Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。
Java NIO: Channels and Buffers(通道和缓冲区)
标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
Java NIO: Non-blocking IO(非阻塞IO)
Java NIO可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似。
Java NIO: Selectors(选择器)
Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
注意:传统IT是单向。 NIO类似

IO和NIO的区别

原有的 IO 是面向流的、阻塞的,NIO 则是面向块的、非阻塞的。

怎么理解IO是面向流的、阻塞的

java1.4以前的io模型,一连接对一个线程。

原始的IO是面向流的,不存在缓存的概念。Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区

Java IO的各种流是阻塞的,这意味着当一个线程调用read或 write方法时,该线程被阻塞,直到有一些数据被读取,或数据完全写入,该线程在此期间不能再干任何事情了。
11111111

可以从通道读取数据到缓冲区,也可以把缓冲区的数据写到通道中

buffer中三个关键属性capacity,position以及limit在读写模式中的说明

多个Channel以事件的方式可以注册到同一个Selector,从而达到用一个线程处理多个请求成为可能。

当你调用Selector的select()或者 selectNow() 方法它只会返回有数据读取的SelectableChannel的实例.

区别

IO NIO
面向流 面向缓冲区
阻塞IO 非阻塞IO
无 选择器**

Buffer的概述

1)容量(capacity):表示Buffer最大数据容量,缓冲区容量不能为负,并且建立后不能修改。
2)限制(limit):第一个不应该读取或者写入的数据的索引,即位于limit后的数据不可以读写。缓冲区的限制不能为负,并且不能大于其容量(capacity)。
3)位置(position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限制(limit)。

实例


public static void main(String[] args) {
  ByteBuffer byteBuffer= ByteBuffer.allocate(1024); try {
  System.out.println(byteBuffer.position());
  System.out.println(byteBuffer.limit());
  System.out.println(byteBuffer.capacity());
  System.out.println("往bytebuffer存放数据:"); byteBuffer.put("你好".getBytes());
  System.out.println(byteBuffer.position());
  System.out.println(byteBuffer.limit());
  System.out.println(byteBuffer.capacity());
  System.out.println("-----------------------"); System.out.println("读取值");
  byteBuffer.flip();//开启读取模式 System.out.println(byteBuffer.position());
  System.out.println(byteBuffer.limit());
  System.out.println(byteBuffer.capacity()); byte[] bytes=new
  byte[byteBuffer.limit()]; byteBuffer.get(bytes); System.out.println(new
  String(bytes,0,bytes.length));
  
  System.out.println("重复读取。。。。。。"); byteBuffer.rewind();//重复读取
  System.out.println("position---"+byteBuffer.position());
  System.out.println(byteBuffer.limit());
  System.out.println(byteBuffer.capacity()); byte[] bytes2=new
  byte[byteBuffer.limit()]; byteBuffer.get(bytes2); System.out.println(new
  String(bytes2,0,bytes2.length));
  
  System.out.println("清空缓存区。。。。。。"); byteBuffer.clear();
  System.out.println("position----"+byteBuffer.position());
  System.out.println(byteBuffer.limit());
  System.out.println(byteBuffer.capacity()); }catch(Exception e) {
  e.printStackTrace(); }
  
  }

4)标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的position,之后可以通过调用reset()方法恢复到这个position。

实例

@Test
	public void testMake() {
		ByteBuffer byteBuffer=ByteBuffer.allocate(14);
		String str="aksjdlfkasjlkf";
		byteBuffer.put(str.getBytes());
		//开启读的模式
		byteBuffer.flip();
		byte[] bytes=new byte[byteBuffer.limit()];
		byteBuffer.get(bytes,0,2);
		byteBuffer.mark();
		System.out.println(new String(bytes,0,2));
		System.out.println(byteBuffer.position());
		
		System.out.println("-----------------------------------");
		byteBuffer.get(bytes,2,2);
		System.out.println(new String(bytes,2,2));
		byteBuffer.reset();
		System.out.println("重置还原到nake标记");
		System.out.println(byteBuffer.position());
	}

(缓冲区)buffer 用于NIO存储数据 支持多种不同的数据类型

  • 1.byteBuffer
  • 2.charBuffer
  • 3.shortBuffer
  • 4.IntBuffer
  • 5.LongBuffer
  • 6.FloatBuffer
  • 7.DubooBuffer
  • 上述缓冲区管理的方式 几乎
  • 通过allocate() 获取缓冲区
  • 二、缓冲区核心的方法 put 存入数据到缓冲区 get
    获取缓冲区数据 flip 开启读模式
  • 三、缓冲区四个核心属性
  • capacity:缓冲区最大容量,一旦声明不能改变。 limit:界面(缓冲区可以操作的数据大小) limit后面的数据不能读写。
  • position:缓冲区正在操作的位置

实例

1、使用nio缓存读取
@Test
public void testFileRead() throws IOException {
long start = System.currentTimeMillis();
//创建管道
FileChannel inChannel = FileChannel.open(Paths.get(“E:\小视频\叶炫清-从前慢.mp3”),StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get(“E:\小视频\叶炫清-从前慢2.mp3”),StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
//定义映射文件
MappedByteBuffer inMappedByte = inChannel.map(MapMode.READ_ONLY,0,inChannel.size());
MappedByteBuffer outMappedByte = outChannel.map(MapMode.READ_WRITE,0,inChannel.size());
//直接缓存读取
byte [] bytes=new byte[inMappedByte.limit()];
inMappedByte.get(bytes);
outMappedByte.put(bytes);
inChannel.close();
outChannel.close();
long end = System.currentTimeMillis();
System.out.println(“读取时间”+(start-end));
}
1、使用普通非缓存的
@Test
public void testFileRead2() throws IOException {
long start = System.currentTimeMillis();
//读取文件
FileInputStream fileInputStream = new FileInputStream(“E:\小视频\\叶炫清-从前慢.mp3”);
FileOutputStream fileOutputStream = new FileOutputStream(“E:\小视频\\叶炫清-从前慢2.mp3”);
//创建通道
FileChannel channel = fileInputStream.getChannel();
FileChannel channel2 = fileOutputStream.getChannel();
ByteBuffer allocate = ByteBuffer.allocate(1024);
while(channel.read(allocate)!=-1) {
channel2.write(allocate);
allocate.clear();
}
channel.close();
channel2.close();
fileOutputStream.close();
fileInputStream.close();
long end = System.currentTimeMillis();
System.out.println(“读取时间”+(start-end));
}

通道(Channel)的原理获取

通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。Channel 负责传输, Buffer 负责存储。通道是由 java.nio.channels 包定义的。 Channel 表示 IO 源与目标打开的连接。Channel 类似于传统的“流”。只不过 Channel本身不能直接访问数据, Channel 只能与Buffer 进行交互。

分散读取与聚集写入

分散读取(scattering Reads):将通道中的数据分散到多个缓冲区中

分散读取(scattering Reads):将通道中的数据分散到多个缓冲区中
聚集写入(gathering Writes):将多个缓冲区的数据聚集到通道中

实例


@Test
	public void testFileRead3() throws IOException {
		long start = System.currentTimeMillis();
		//读取文件
		RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt","rw");
		//创建通道--分散读取文件内容
		FileChannel channel = randomAccessFile.getChannel();
		ByteBuffer allocate = ByteBuffer.allocate(1024);
		ByteBuffer allocate2 = ByteBuffer.allocate(1024);
		ByteBuffer [] buf2= {allocate,allocate2};
		channel.read(buf2);
		for (ByteBuffer byteBuffer : buf2) {
			//读取模式
			byteBuffer.flip();
		}
		System.out.println(new String(buf2[0].array(),0,buf2[0].limit()));
		System.out.println("000000000000000000000000000000000000000000000");
		System.out.println(new String(buf2[0].array(),0,buf2[0].limit()));
		System.out.println("聚集读取:");
		//读取文件
		RandomAccessFile randomAccessFile2=new RandomAccessFile("test2.txt", "rw");
		//创建通道---聚集写入文件
		FileChannel channe2 = randomAccessFile.getChannel();
		channe2.write(buf2);
	
		randomAccessFile.close();
		randomAccessFile2.close();
		long end = System.currentTimeMillis();
		System.out.println("读取时间"+(start-end));
	}

字符集 Charset

编码:字符串->字节数组
解码:字节数组 -> 字符串

实例

// 获取编码器

		Charset cs1 = Charset.forName("GBK");
		// 获取编码器
		CharsetEncoder ce = cs1.newEncoder();
		// 获取解码器
		CharsetDecoder cd = cs1.newDecoder();
		CharBuffer cBuf = CharBuffer.allocate(1024);
		cBuf.put("蚂蚁课堂牛逼!");
		cBuf.flip();
		// 编码
		ByteBuffer bBuf = ce.encode(cBuf);
		for (int i = 0; i < 12; i++) {
			System.out.println(bBuf.get());
		}
		// 解码
		bBuf.flip();
		CharBuffer cBuf2 = cd.decode(bBuf);
		System.out.println(cBuf2.toString());
		System.out.println("-------------------------------------");
		Charset cs2 = Charset.forName("GBK");
		bBuf.flip();
		CharBuffer cbeef = cs2.decode(bBuf);
		System.out.println(cbeef.toString());
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知青先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值