来看看美国人的速度——纽约加速纯电动大巴应用

1. 简述

Java NIO(new io non blocking io)是从java1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有着同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。

2. Java NIO 与 IO的主要区别

1. Java NIO概述

2.1 图解(面向流和面向缓冲区)

1. Java NIO概述

1. Java NIO概述

3. Java NIO 的 通道(channel)与缓冲区(buffer)

1. Java NIO概述

一句话总结:Channel负责传输,Buffer负责存储

3.1 缓冲区(buffer)

1. Java NIO概述

3.1.1 直接缓冲区 与 非直接缓冲区

1. Java NIO概述

  • 非直接缓冲区:通过 allocate()方法分配缓冲区,将缓冲区建立在 JVM 内存中
  • 直接缓冲区:通过 allocateDirect()方法分配直接缓冲区,将缓冲区建立再操作系统的物理内存中。在某种情况下可以提高效率
1. Java NIO概述

1. Java NIO概述

package com.wj.nio;

import java.nio.ByteBuffer;

/**
* 一. 缓冲区:再Java NIO中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据
*
* 根据数据类型不同(boolean除外),提供了对应类型的缓冲区
* ByteBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* CharBuffer
* DoubleBuffer
* FloatBuffer
*
* 上述缓冲区的管理方式都基本一致,通过allocate()获取缓冲区
*
* 二. 缓冲区存储数据的两个核心方法
* put() :存入数据到缓冲区
* get() :获取缓冲中的数据
*
* 三:缓冲区中的四个核心属性:
* capacity:容量,表示缓冲区中最大存储数据的容量。一旦声明,不能改变
* limit:界限,表示缓冲区中可以操作数据的大小。(limit后面的数据是不能进行读写的)
* position:位置,表示缓冲区中正在操作数据的位置
* mark:标识,表示记录当前position的位置。可通过reset()恢复到mark的位置
*
* Invariants: 0 <= mark <= position <= limit <= capacity
*
* 四:直接缓冲区 与 非直接缓冲区
* 非直接缓冲区:通过 allocate()方法分配缓冲区,将缓冲区建立在 JVM 内存中
* 直接缓冲区:通过 allocateDirect()方法分配直接缓冲区,将缓冲区建立再操作系统的物理内存中。在某种情况下可以提高效率
*/
public class TestBuffer {
public static void main(String[] args) {
// test1();
// test2();
test3();
}

public static void test3(){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); // 直接缓冲区

// 判断缓冲区是否时直接的
System.out.println(\"直接缓冲区:\" + byteBuffer.isDirect());

}

public static void test2(){
String str = \"abcde\";

ByteBuffer bf = ByteBuffer.allocate(1024); // 非直接缓冲区
bf.put(str.getBytes());

// 切换到读取模式
bf.flip();

// 读取数据
byte[] b1 = new byte[bf.limit()];
bf.get(b1,0,2);
System.out.println(new String(b1));
System.out.println(bf.position());

// 进行定位标记
bf.mark();

bf.get(b1,2,2);
System.out.println(new String(b1));
System.out.println(bf.position());

// reset() 恢复到mark的位置
bf.reset();
System.out.println(bf.position());

}

public static void test1(){
String str = \"abcde\";

// 1. 分配一个指定大小的缓冲区
ByteBuffer allocate = ByteBuffer.allocate(1024); // 非直接缓冲区
System.out.println(\"-----------------allocate----------------\");
System.out.println(allocate.position()); // 位置
System.out.println(allocate.limit()); // 界限
System.out.println(allocate.capacity()); // 容量

// 2. 利用put()添加数据
allocate.put(str.getBytes());
System.out.println(\"-----------------put()----------------\");
System.out.println(allocate.position()); // 位置
System.out.println(allocate.limit()); // 界限
System.out.println(allocate.capacity()); // 容量

// 3. 切换成读取数据的模式
allocate.flip();
System.out.println(\"-----------------flip()----------------\");
System.out.println(allocate.position()); // 位置
System.out.println(allocate.limit()); // 界限
System.out.println(allocate.capacity()); // 容量

// 4. 读取缓冲区数据
byte[] dst = new byte[allocate.limit()];
allocate.get(dst);
System.out.println(\"-----------------get()----------------\");
System.out.println(new String(dst,0,dst.length));
System.out.println(allocate.position()); // 位置
System.out.println(allocate.limit()); // 界限
System.out.println(allocate.capacity()); // 容量

// 5. rewind() 重读
allocate.rewind();
System.out.println(\"-----------------rewind()----------------\");
System.out.println(allocate.position()); // 位置
System.out.println(allocate.limit()); // 界限
System.out.println(allocate.capacity()); // 容量

// 5.clear() 清空缓冲区,但是缓冲区中的数据依然存在,只不过数据处于被遗忘状态,就是指针回到原始状态,但是数据没丢
allocate.clear();
System.out.println(\"-----------------clear()----------------\");
System.out.println(allocate.position()); // 位置
System.out.println(allocate.limit()); // 界限
System.out.println(allocate.capacity()); // 容量
}
}

3.2 通道(channel)

1. Java NIO概述

3.2.1 通道演化图解

1. Java NIO概述

  • 由CPU独立负责IO接口,当发起大量请求时,CPU占用率就会非常高,导致CPU无法做其他工作。
1. Java NIO概述

  • DMA(直接存储器存储):当有请求IO操作时,DMA向CPU申请权限,那么所有的IO接口将由DMA全权进行处理。传统IO操作就是这种方式。但是这种方式也有缺陷:当有非常大的应用程序发起大量的IO读写请求时,DMA会创建大量的DMA总线,造成冲突,最终造成资源浪费。
1. Java NIO概述

  • 通道(Channel):完全独立的处理器,专门用于IO操作。,虽然依附于CPU,但是和CPU没有任何关系,不会牵连到CPU。

3.2.2 Java为Channel接口提供的最主要实现类如下:

1. Java NIO概述

3.2.3 分散(Scatter)和聚集(Gather)

1. Java NIO概述

1. Java NIO概述

package com.wj.nio;


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Map;

/**
* 一:通道(Channel):用于源节点与目标节点的链接,再Java NIO中负责缓冲区中数据的传输。Channel本省不存储数据,因此需要配合缓冲区进行传输操作。
*
* 二:通道的一些主要实现类:
* java.nio.channels.Channel
* |--FileChannel:完成本地文件数据传输
* |--SocketChannel:通过TCP读取网络中的数据
* |--ServerSocketChannel:监听新进来的TCP连接,对每一个连接创建SocketChannel
* |--DatagramChannel:通过UDP读取网络中的数据
*
* 三:获取通道
* 1. Java针对支持通道的类提供了 getChannel() 方法,
* 本地IO:
* FileInputStream/FileOutputStream
* RandomAccessFile:随即存储文件流
* 网络IO:
* Socket
* ServerSocket
* DatagramSocket
*
* 2. jdk1.7中的NIO.2对NIO进行了更新。正对各个通道提供了静态放法 open()
*
* 3. jdk1.7中的NIO.2的File工具类的newByteChannel()
*
* 四、通道之间的数据传输
* transfreFrom()
* transfreTo()
*
* 五、分散(Scatter)于聚集(Gather)
* 分散读取(Scatter Reads):将通道中的数据分散到多个缓冲区
* 聚集写入(Gather Writes):将多个缓冲区的数据聚集到通道中
*
* 六:字符集:Charset
* 编码:字符串转换为字节数组
* 解码:字节数组转换为字符串
*/
public class TestChannel {
public static void main(String[] args) throws Exception {
// test01(); // 基于流的通道
// test02(); // open()方式的通道
// test03(); // 通道之间的数据传输
// test04(); // 分散(scatter)于聚集(Gather)
// test05(); // 字符集的编码与解码
test06(); // 字符集的编码与解码

}

/**
* 字符集的编码与解码
*/
private static void test06() throws Exception {
// 创建字符集
Charset gbk = Charset.forName(\"GBK\");
// 获取编码器
CharsetEncoder charsetEncoder = gbk.newEncoder();
// 获取解码器
CharsetDecoder charsetDecoder = gbk.newDecoder();

//
CharBuffer allocate = CharBuffer.allocate(1024);
allocate.put(\"测试编码\");
allocate.flip();

// 编码
ByteBuffer encode = charsetEncoder.encode(allocate);
for (int i=0; i<8;i++) {
System.out.println(encode.get());
}
encode.flip();

// 解码
CharBuffer decode = charsetDecoder.decode(encode);

System.out.println(decode.toString());
}

/**
* 查询支持的编码格式
*/
private static void test05() {
Map<String, Charset> stringCharsetSortedMap = Charset.availableCharsets();
// 查询支持的编码格式
for(Map.Entry<String, Charset> en : stringCharsetSortedMap.entrySet()){
System.out.println(en.getKey() + \"=\" + en.getValue());
}

}

/**
* 分散(scatter)于聚集(Gather)
*/
private static void test04() throws Exception {
RandomAccessFile raf = new RandomAccessFile(\"srcurl\",\"rw\");

// 1. 获取通道
FileChannel channel = raf.getChannel();

// 2. 创建缓冲区
ByteBuffer bf1 = ByteBuffer.allocate(100);
ByteBuffer bf2 = ByteBuffer.allocate(1024);

// 3. 分散读取
ByteBuffer[] bfs = {bf1,bf2};
channel.read(bfs);

for (ByteBuffer byteBuffer : bfs) {
byteBuffer.flip();
}

// 测试
System.out.println(new String(bfs[0].array(), 0, bfs[0].limit()));
System.out.println(\"-------------------\");
System.out.println(new String(bfs[1].array(), 0, bfs[1].limit()));

// 聚集写入操作
RandomAccessFile raf2 = new RandomAccessFile(\"dsturl\",\"rw\");
FileChannel channel2 = raf2.getChannel();
channel2.write(bfs);

//
raf.close();
channel.close();
channel2.close();
}


/**
* 通道之间的数据传输
*/
private static void test03() throws Exception{
FileChannel inChannel = FileChannel.open(Paths.get(\"srcurl\"), StandardOpenOption.READ); // 都属性
FileChannel outChannel = FileChannel.open(Paths.get(\"dsturl\"), StandardOpenOption.READ, StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW); // 写属性,不存在就创建,存在就报错

inChannel.transferTo(0,inChannel.size(),outChannel); // 也是直接缓冲区
// outChannel.transferFrom(inChannel,0,inChannel.size()); // 和上面的一样

inChannel.close();
outChannel.close();
}

/**
* 使用 open() 创建通道 直接使用通道效率高于基于流的通道
*/
private static void test02() throws Exception{
FileChannel inChannel = FileChannel.open(Paths.get(\"srcurl\"), StandardOpenOption.READ); // 都属性
FileChannel outChannel = FileChannel.open(Paths.get(\"dsturl\"), StandardOpenOption.READ, StandardOpenOption.WRITE,StandardOpenOption.CREATE_NEW); // 写属性,不存在就创建,存在就报错

// 创建直接缓存(FileChannel方式)
MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());

// 直接对缓冲区进行数据的读写操作
byte[] bst = new byte[inMappedBuf.limit()];
inMappedBuf.get(bst);
outMappedBuf.put(bst);

inChannel.close();
outChannel.close();
}


/**
* 利用通道完成文件的复制
* @throws Exception
*/
public static void test01() throws Exception{
FileInputStream fis = new FileInputStream(\"srcurl\");
FileOutputStream fos = new FileOutputStream(\"dsturl\");

// 创建非直接缓存区
ByteBuffer bf = ByteBuffer.allocate(1024);

// 创建通道
FileChannel inchannel = fis.getChannel();
FileChannel outchannel = fos.getChannel();

// 数据传输
while(inchannel.read(bf) != -1){
// 切换为读取模式
bf.flip();
// 将数据输出
outchannel.write(bf);
// 清空缓存
bf.clear();
}

// 关闭流
if(fis != null){
fis.close();
}
if(fos != null){
fos.close();
}
if(inchannel != null){
inchannel.close();
}
if(outchannel != null){
outchannel.close();
}

}
}
上一篇

当爱豆遇上“卸妆水”,华晨宇没变化,看到黄子韬:像变了个人

下一篇

深入地下一万米,带你进入地下的奇幻之旅

评论已经被关闭。

插入图片
返回顶部