目录
IO
IO:Blocking IO 同步阻塞
使用输入机制,允许程序读取外部数据(包括俩字磁盘、光盘等存储设备的数据)、用户输入数据
使用输出机制,允许程序记录运行状态,将程序数据输出到磁盘、光盘等存储设备中。
File类
IO原理
IO流用来处理设备之间的数据传输。
Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。
流的分类:
Java使用处理流来包装节点流是一种典型的装饰器设计模式。
NIO(New IO)
NIO与IO区别
阻塞与非阻塞:
NIO核心:
若使用NIO系统,需要获取用于连接IO设备的通道一级用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。
采用内存映射文件的方式来处理输入/输出。将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了,这种方式比传统的要快。
Channel负责传输,Buffer负责存储。Channel类似于铁路,Buffer类似于火车。
1、Channel(通道)
类似于:铁路
通道表示打开IO设备(例如:文件、套接字)的连接。Channel本身不存储数据,只能与Buffer进行交互。
所有数据都需要通过通道传输;Channel与传统的InputStream、OutputStream的最大区别在于:它提供了一个map()方法,通过该map()方法可以直接将“一块数据”映射到内存中。如果传统的面向流,则NIO面向块的处理。
利用通道完成文件的复制(非直接缓冲区)
// 利用通道完成文件的复制(非直接缓冲区)
@Test
public void test2() throws IOException {
FileInputStream fis = null;
FileOutputStream fos = null;
// 获取通道
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
fis = new FileInputStream("G:\\学习资料2019\\nio\\1.jpg");
fos = new FileOutputStream("2.jpg");
// 获取通道
inChannel = fis.getChannel();
outChannel = fos.getChannel();
// 分配指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
// 将通道中的数据存入缓冲区
while (inChannel.read(buf) != -1) {
buf.flip(); // 切换读取数据的模式
// 将缓冲区中的数据写入通道中
outChannel.write(buf);
buf.clear();// 清空缓存区
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
利用直接缓冲区完成文件的赋值(内存映射文件)
// 使用直接缓冲区完成文件的复制(内存映射文件)
@Test
public void test3() throws IOException{
long start = System.currentTimeMillis();
FileChannel inChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ, StandardOpenOption.CREATE);
// 内存映射文件
MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0,inChannel.size());
MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0,inChannel.size());
// 直接对缓冲区进行数据的读写操作
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMappedBuf.put(dst);
inChannel.close();
outChannel.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
通道之间的数据传输(直接缓冲区)
// 通道之间的数据传输
@Test
public void test4() throws IOException {
FileChannel inChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("5.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ, StandardOpenOption.CREATE);
// inChannel.transferTo(0,inChannel.size(),outChannel);
outChannel.transferFrom(inChannel,0,inChannel.size());
inChannel.close();
outChannel.close();
}
分散(Scatter)和聚集(Gather)
分散读取:
@Test
public void test5() throws IOException{
RandomAccessFile raf1 = new RandomAccessFile("1.txt","rw");
// 获取通道
FileChannel channel = raf1.getChannel();
// 分配指定大小的缓冲区
ByteBuffer buf1 = ByteBuffer.allocate(1);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
// 分散读取
ByteBuffer[] bufs = {buf1,buf2};
channel.read(bufs);
for (ByteBuffer byteBuffer:bufs
) {
byteBuffer.flip();
}
System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));;
System.out.println("-------------------------------");
System.out.println(new String (bufs[1].array(),0,bufs[1].limit()));
}
聚集写入:
@Test
public void test5() throws IOException{
RandomAccessFile raf1 = new RandomAccessFile("1.txt","rw");
// 获取通道
FileChannel channel = raf1.getChannel();
// 分配指定大小的缓冲区
ByteBuffer buf1 = ByteBuffer.allocate(1);
ByteBuffer buf2 = ByteBuffer.allocate(1024);
// 分散读取
ByteBuffer[] bufs = {buf1,buf2};
channel.read(bufs);
for (ByteBuffer byteBuffer:bufs
) {
byteBuffer.flip();
}
System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));;
System.out.println("-------------------------------");
System.out.println(new String (bufs[1].array(),0,bufs[1].limit()));
// 聚集写入
RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
FileChannel channel2 = raf2.getChannel();
channel2.write(bufs);
}
2、Buffer(缓冲)
类似于:火车
负责数据的存取。
可以理解成一个容器,本质是一个数组,发送到Channel中的所有对象都必须首先放到Buffer中,从而Channel中读取的数据也必须先放到Buffer中。
Buffer可以一次次去Channel中共取数据,也允许Channel直接将文件的某块数据映射成Buffer。
类型、方法、属性
示例:
@Test
public void test1() {
System.out.println("--------------allocate-------------------");
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
System.out.println("-----------------put----------------");
// 利用put存入数据到缓冲区
String str = "abcde";
byteBuffer.put(str.getBytes());
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
System.out.println("-----------------flip()----------------");
// 切换到读取数据的模式
byteBuffer.flip();
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
System.out.println("-----------------get()----------------");
// 利用get()读取缓冲区中的数据
byte[] bytes = new byte[byteBuffer.limit()];
byteBuffer.get(bytes);
System.out.println(new String(bytes, 0, bytes.length));
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
System.out.println("-----------------rewind()----------------");
// 可重复读数据
byteBuffer.rewind();
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
System.out.println("-----------------clear()----------------");
// clear()清空缓冲区,但是缓冲区中的数据依然存在,但是处于“被遗忘状态”,不能正确的读取数据
byteBuffer.clear();
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
}
3、Selector(选择器)