IO和NIO区别:
其本质就是阻塞和非阻塞的区别。
阻塞的概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,就会一直等待,直到传输完毕。
非阻塞概念:应用程序直接可以获取已经准备就绪好的数据,无需等待。
IO为同步阻塞形式,NIO为非同步阻塞形式,NIO病咩有实现异步,在JDK1.7后升级NIO库包,支持异步非阻塞同步模型NIO2.0;
IO模式:同步阻塞模式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的请求都会注册到多路复用器上,多路复用轮询到连接有IO请求时才启动一个线程进行处理。
AIO:异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的IO请求都是有OS先完成了再通知服务器应用去启动线程进行处理。
同步时,应用程序会直接参与IO读写操作,并且我们的应用程序会直接阻塞到某个方法上,直到数据准备就绪,或者采用轮询的策略实时检查就绪状态,如果就绪则获取数据。
异步时,则所有的IO读写教程操作系统,与我们的应用程序无关,我们程序不需要关系IO读写,当请求系统完车了IO读写操作时,会给我们的应用程序发送通知吗,我们的应用程序直接拿走数据就可以了。
断点续传:
多线程加上文件的拼接组成的。
Buffer缓冲区的用法:
实现缓冲区的读写操作:
@Test
public void test01(){
//初始化buffer容量。
allocate = ByteBuffer.allocate(1024);
System.out.println("=======>>>>>>缓存区可用大小:"+ allocate.limit());
System.out.println("==========>>>>缓冲区正在操作的位置:"+ allocate.position());
System.out.println("==========>>>>>缓存区最大的容量:"+ allocate.capacity());
System.out.println("==========>>>>缓冲区存放数据:");
allocate.put("1234567".getBytes());
System.out.println("=======>>>>>>缓存区可用大小:"+ allocate.limit());
System.out.println("==========>>>>缓冲区正在操作的位置:"+ allocate.position());
System.out.println("==========>>>>>缓存区最大的容量:"+ allocate.capacity());
allocate.flip();//开启读取模式
byte [] bytes = new byte[allocate.limit()];
allocate.get(bytes);
System.out.println("==========>>>>>>读取的数据是:"+new String(bytes,0,bytes.length));
System.out.println("==========>>>>>>>重复读取");
allocate.rewind();//开启重复读取模式
byte [] bytes1 = new byte[allocate.limit()];
allocate.get(bytes1);
System.out.println("==========>>>>>>读取的数据是:"+new String(bytes1,0,bytes1.length));
System.out.println("清空缓冲区:"+allocate.clear());
System.out.println("=======>>>>>>缓存区可用大小:"+ allocate.limit());
System.out.println("==========>>>>缓冲区正在操作的位置:"+ allocate.position());
System.out.println("==========>>>>>缓存区最大的容量:"+ allocate.capacity());
System.out.println((char)allocate.get());
}
mark和rest用法的区别:
标记:mark与重制rest:
标记是一个索引,通过Buffer中的mark()方法中一个特定的posiotion,之后可以通过reset()方法恢复搭配这个position。
@Test
public void test02(){
ByteBuffer byteBuffer =ByteBuffer.allocate(10);//初始化,Byte的容量设置为10,
byteBuffer.put("abcdefg".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,0,2));
byteBuffer.reset();//恢复到mark位置标记
System.out.println(byteBuffer.position());
}
缓存区分为直接缓存区和非直接缓存区:
非直接缓存区主要存存放jvm缓存区中,
直接缓存区主要存放在物理内存中。
存放在物理内存中效率比较高。
非直接缓存区更加安全。
直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法来创建。
通道(Channel)的原理的获取:
通道表示打开到IO设备(例如:文件,套接字)的连接,若需要使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓存区,然后操作缓存区,对数据进行处理,Channel负责传输,Buffer赋值存储,通道是有Java.io.channels 包定义的Channle表示IO源与目标打开的连接。Channle类似于传统的流,只不过Channel本身不能直接访问数据,Channle只能与Buffer进行交互。
Java.nio.channels.Channel接口:
FileChannel:
SocketChannel:
ServerSocketChannel:
DatagramChannel:
获取通道:
1.Java针对支持通道的类提供了getChannel()方法
本地io:
FileInputStream/FileOutPutStream()
RandomAccessFile()
网络IO :
Socket:
ServerSocket:
DataGramSocket:
2.在JDK1.7中NIO.2提供了针对各个通道提供了静态的方法open()
3.在JDK1.7中NIO.2 中Files工具类的newByteChannel().
@Test
public void test03()throws Exception{
//读入流
FileInputStream fileInputStream = new FileInputStream("/Users/yantianpeng/Desktop/11.png");
//写入流
FileOutputStream fileOutputStream = new FileOutputStream("/Users/yantianpeng/Desktop/2.png");
//创建读入通道
FileChannel channel = fileInputStream.getChannel();
//创建写入通道
FileChannel channel1 = fileOutputStream.getChannel();//非缓存区读取操作
//分配指定大小缓存区
ByteBuffer allocate = ByteBuffer.allocate(1024);
while (channel.read(allocate)!=-1){
//开启读写模式
allocate.flip();
channel1.write(allocate);
allocate.clear();//buffer必须clear
}
channel1.close();
channel.close();
fileOutputStream.close();
fileOutputStream.close();
}
分散读取:将通道中的数据分散到多个缓冲区中。
聚集写入:将多个缓存区的数据聚集到通道中。
/**
* 非散读取:将通道中的数据分散到多个缓冲区中。
* 聚集写入:将多个缓存区的数据聚集到通道中。
*/
@Test
public void test05() throws Exception{
//随机访问
RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/yantianpeng/Desktop/1.txt", "rw");
//获取通道
FileChannel channel = randomAccessFile.getChannel();
//分配指定大小指定缓存区
ByteBuffer allocate1 = ByteBuffer.allocate(100);
ByteBuffer allocate2 = ByteBuffer.allocate(1024);
ByteBuffer [] bufs= {allocate1,allocate2};
channel.read(bufs);
for (ByteBuffer byteBuffer: bufs) {
byteBuffer.flip();//开启读写模式
}
String string =new java.lang.String(bufs[0].array(),0,bufs[0].limit());
System.out.println(string);
System.out.println("=======================================");
System.out.println(new String(bufs[1].array(),1,bufs[1].limit()));
System.out.println("==========>>>>>>>>>>>聚集读写操作");
RandomAccessFile randomAccessFile1 = new RandomAccessFile("/Users/yantianpeng/Desktop/2.txt ", "rw");
//获取通道
FileChannel channel1 = randomAccessFile1.getChannel();
channel1.write(bufs);
randomAccessFile1.close();
randomAccessFile.close();
}