Jdk 1.4+ New IO 面向通道和缓冲区
所在包:java.nio
数据总数由通道写入到buffer , 或者是从buffer写入通道
完全替换IO(面向流 单向的)
1. channel 通道
2. Buffer 缓冲区
3. Selector 选择器
1. 传统的IO面向流 ,NIO面向缓冲区
2. 传统的IO是阻塞IO ,NIO是非阻塞IO(可并行,,可占位)
3. NOI增加了新功能
① 由选择器
② 可以使用正则表达式
③ 支持内存映射(计算快,效率快)
④ 支持文件锁
本质上就是一个数据集 数组?集合?
本质是一个可以写入数据,并且从中读取数据的内存!!!
存储的是相同数据类型的数据集
1. Position:写入或者读取的数据的当前指针
2. Limit:有多少数据可以写或者可以读
3. Capacity:缓冲区的最大容量
limit 和 capacity 值一致
Position 最大 值{下标(0开始)}是capacity-1
写到哪 值是什么 从0开始
指针的值是 真实值+1 --> 将要写的位置 (最大到capacity值)
xxxBuffer buffer = xxxBuffer.allocate(最大容量);
Buffer.put(xx); 写入数据
Position 读到那值值是几,,但从0开始
Limit 的值是position写模式的值(可读数据)
重设缓冲区 切换到读模式
Buffer.flip();
package com.fsdm.nio.buffer;
import java.nio.IntBuffer;
/**
* @author 房上的猫
* @create 2018-07-03 17:11
* @博客地址: https://www.cnblogs.com/lsy131479/
* <p>
* NIO 初探缓冲区
**/
public class BufferTest {
public static void main(String[] args) {
//创建缓冲区实例
IntBuffer buffer = IntBuffer.allocate(10);
System.out.println( "\n\n=====================写操作====================\n\n");
//监控各值
System.out.println( "*************** 写模式初始值 ***************");
System.out.println( "capacity=== » " +buffer.capacity());
System.out.println( "position=== » " +buffer.position());
System.out.println( "limit===» "+buffer. limit());
//写入数据
buffer.put(new int[]{1,1,1,2});
//监控各值
System.out.println( "*************** 写入值后 ***************");
System.out.println( "capacity=== » " +buffer.capacity());
System.out.println( "position=== » " +buffer.position());
System.out.println( "limit===» "+buffer. limit());
//重设缓冲区 切换到读模式
buffer.flip();
System.out.println( "\n\n====================读操作=====================\n\n");
//监控各值
System.out.println( "*************** 读模式初始值 ***************");
System.out.println( "capacity=== » " +buffer.capacity());
System.out.println( "position=== » " +buffer.position());
System.out.println( "limit===» "+buffer. limit());
//简单的读操作
while (buffer.hasRemaining()){
System.out.println(buffer.get());
//监控各值
System.out.println( "*************** 读取中 ***************");
System.out.println( "capacity=== » " +buffer.capacity());
System.out.println( "position=== » " +buffer.position());
System.out.println( "limit===» "+buffer. limit());
}
}
}
1. 基于buffer(缓冲区)对数据进行读写
2. 管道是双向的,流是单向的
3. 可以异步的读写
网络传输:
UDP:面向非连接,无脑流,效率高,性能好,非安全
TCP:面向连接,效率低,性能差,安全
1. FileChannel:从文件中读写数据
2. DataGrarmChannel:通过UDP来读写网络中数据
3. SocketChannel:通过TCP读写网络中的数据
4. ServerSocketChannel:可以监听新来的TCP连接,每进来一个,都会创建一个新的 SocketChannel
小Tip:
package com.fsdm.nio.channel;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.FileChannel;
/**
* @author 房上的猫
* @create 2018-07-05 14:09
* @博客地址: https://www.cnblogs.com/lsy131479/
* <p>
* 通过管道向文件中读写数据
**/
public class ChannelDemo {
public static void main(String[] args) {
//准备数据
String[] strs = {"haha","hehe","heihei"};
//写入 文件 输出流
FileOutputStream fos=null;
//准备管道
FileChannel channel = null;
try {
fos = new FileOutputStream("f:/a.txt");
//获取管道数据
channel = fos.getChannel();
//准备缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
//将事先准备好的数据 写入缓冲区
for (String str:strs) {
buffer.put(str.getBytes());
buffer.put("\n".getBytes());
}
//将缓存区切换到读模式
buffer.flip();
//将缓冲区数据读取出来并写入磁盘 真正的写
channel.write(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//回收资源
try {
channel.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
练习实例:(利用管道将a文件内容复制到b文件):
package com.fsdm.nio.channel;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
/**
* @author 房上的猫
* @create 2018-07-05 15:02
* @博客地址: https://www.cnblogs.com/lsy131479/
* <p>
* a.txt --> b.txt
**/
public class ChannelBuffer {
public static void main(String[] args) {
//准备起始文件与终止文件
File inFile = new File("f:/a.txt");
File outFile = new File("f:/b.txt");
//准备输入输出流
FileInputStream fis = null;
FileOutputStream fos = null;
//准备双向管道
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
//实例化各对象
fis = new FileInputStream(inFile);
fos = new FileOutputStream(outFile);
inChannel = fis.getChannel();
outChannel = fos.getChannel();
//准备缓存区 (作为中转站)
ByteBuffer buffer = ByteBuffer.allocate(1024);
int num = 0;
//写入到缓冲区
while ((num=inChannel.read(buffer))!=-1){
//转换缓冲区模式
buffer.flip();
//读取缓冲区数据并写入到磁盘
outChannel.write(buffer);
//清空缓冲区 方便下次读写
buffer.clear();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
inChannel.close();
fis.close();
outChannel.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
待后期单独总结
高并发:NIO,线程
运行时都会被创建
共享数据:
堆 heap
方法区 method area
私有数据:
虚拟机栈 vm stack
本地方法栈 native method stack
程序计数器
Xms:初始化容量
Xmx:最大容量
就是把文件映射到电脑中的内存中,通过操作内存从而打到操作文件的目的
内存中操作速度是最快的
1. RandomAceessFile 随机读取,速度最慢
2. FileInputStream 流的方式读取
3. BufferReader 缓存的方式读取
4. MappedByteBuffer 内存映射,速度最快
1. READ_ONLY :对缓冲区的内存只读
2. READ_WRITE :对缓冲区的内存读写
3. PRIVATE :只会对缓冲区的内存进行修改,不会影响到真实的文件
通常适用于数据的读取,一般不会进行对数据的写入
内存映射读取文件与普通读取文件 效率对比:
package com.fsdm.nio;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
/**
* @author 房上的猫
* @create 2018-07-05 18:00
* @博客地址: https://www.cnblogs.com/lsy131479/
* <p>
* 内存映射
**/
public class MapperDemo {
public static void main(String[] args) {
FileChannel channel = null;
RandomAccessFile file = null;
try {
file = new RandomAccessFile("e:/struts-2.3.31-lib.zip","rw");
//获取通道
channel = file.getChannel();
//创建内存映射对象
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,channel.size());
byte[] bytes = new byte[1024];
//获取文件大小
long length = file.length();
long begin = System.currentTimeMillis();
ByteBuffer buffer2 = ByteBuffer.allocate(1024);
for (int i=0;i<length;i+=1024){
if (length-i>1024){
buffer2=buffer.get(bytes);
}else{
buffer2=buffer.get(new byte[(int)(length-i)]);
}
buffer2.flip();
buffer2.clear();
}
long end = System.currentTimeMillis();
System.out.println(end-begin);
System.out.println("================");
begin = System.currentTimeMillis();
//普通读取缓冲区
ByteBuffer buffer1 = ByteBuffer.allocate(1024);
while (channel.read(buffer1)!=-1){
buffer1.flip();
buffer.clear();
}
end = System.currentTimeMillis();
System.out.println(end-begin);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileLock :基于FlieChannel对文件提供锁的功能
共享读的操作
读可以有多个,但是只能有一个人在写
适合读取数据
目的:是为了防止其他线程拿到独占锁
只能有一个读或写
读写不能同时
适合写数据
阻塞
无参默认是独占锁
有参的可设置锁状态
非阻塞
package com.fsdm.nio.lock;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
/**
* @author 房上的猫
* @create 2018-07-05 18:15
* @博客地址: https://www.cnblogs.com/lsy131479/
* <p>
* 锁
**/
public class LockDemo implements Runnable {
static RandomAccessFile file = null;
static FileChannel channel = null;
static FileLock lock = null;
public static void main(String[] args) {
Thread thread = null;
try {
// lock = channel.lock(0L, Long.MAX_VALUE, true);
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
try {
file = new RandomAccessFile("f:/a.txt", "rw");
channel = file.getChannel();
if (i==0){
lock = channel.lock();
// lock = channel.lock(0L, Long.MAX_VALUE, true);
buffer.put("xx".getBytes());
}
} catch (Exception e) {
e.printStackTrace();
}
LockDemo lockDemo = new LockDemo();
thread = new Thread(lockDemo, i+":");
thread.start();
}
try {
System.out.println(Thread.currentThread().getName()+(char)( channel.write(buffer)));
} catch (IOException e) {
e.printStackTrace();
}
;
}
static ByteBuffer buffer = ByteBuffer.allocate(1024);
@Override
public void run() {
try {
buffer =ByteBuffer.allocate(1024);
buffer.put("xx".getBytes());
System.out.println(Thread.currentThread().getName()+(char)( channel.write(buffer)));;
//System.out.println(Thread.currentThread().getName()+(char)( channel.read(buffer)));;
} catch (Exception e){
e.printStackTrace();
}
}
}