java Nio
java Nio
1.非直接缓存
2.直接缓冲
电脑蓝屏上面的内容丢失;
3.通道:Channel
远古的IO操作:由cpu作为中央处理器,如果应用程序需要读取写入物理硬盘,调用cpu的接口进行读写操作,这样会会使cpu性能急速的下降,不能再更好的处理其他任务了。
改进之后的IO流
直接存储器存储DMA
当应用程序发送一个读写请求时,DMA会向CPU申请权限,如果CPU同意,那么接下来的读写IO接口全都由DMA(直接存储器DMA)负责处理操作,建立DMA总线,每一次读写操作都会建立一次连接线;
优点:
? CPU不需要干预,CPU能做更多的事情
缺点:
? 如果是非常大的应用程序,发起大量的读写请求时,需要建立大量的DMA总线,如果总线过多会出现总线冲突的问题,会影响到性能。
再次更新后的IO通道:
CPU是中央处理器,而在通道哪一块它也是一块处理器,是独立的,是用于IO操作的,拥有自己传输方式,它附属于CPU。
实际上IO流和通道方式基本上没有什么区别,但是如果是大量的io请求,通道方法会优于io流,因为cpu的利用率更高,连请求权限都不需要申请直接读写操作。
java中使用通道
-
通道
源节点和目标节点的连接通道,在java Nio中负责缓冲区数据的传输。通道Channel 本身不存储数据,因此需要配合缓冲区进行传输。
-
ava.nio.channels;
继承
通道的间接实现Channels
java.nio.channels.FileChannel 文件通道 java.nio.channels.SocketChannel 网络通道 java.nio.channels.ServerSocketChannel 服务端通道 java.nio.channels.DatagramChannel 数据通道
-
获取通道有三种方式:
-
jdk1.4
通过使用:getChannel()方法
-
本地IO通道:
FileInputStream FileOutputStream RandomAccessFile
-
网路IO通道
Socket ServerScoket DatagramSocket
? 2.jdk 1.7 对 Nio 改动升级 Nio 2.
? 各个通道之间提供了 open()方法获取通道
? 3.File工具类的nweByteChannel()获取通道
本地IO通道
FileInputStream 文件输入流
FileOutputStream 文件输出流
RandomAccessFile 随机访问文件流
代码实践:
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
/**
* 通道(Channel): 源节点和目标节点的连接通道
*/
public class ChannelDemo {
/**
* 直接缓冲区,
* 在复制过程过程中,文件已经复制完毕了,但是java的垃圾回收机制没有及时回收,导致内存映射文件一直占用资源,偶尔会出现
*/
@Test
public void directBuffer() throws IOException {
FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.READ);
// 内存映射文件
MappedByteBuffer inMap = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMap = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
byte[] bytes = new byte[inMap.limit()];
inMap.get(bytes); // 读取
outMap.put(bytes);// 写入
inChannel.close();
outChannel.close();
}
/**
* 非直接缓冲区文件复制
*/
@Test
public void inputAndOutput() throws IOException {
// 利用通道完成读写操作
FileInputStream fileInputStream = new FileInputStream("1.png");
FileOutputStream fileOutputStream = new FileOutputStream("2.png");
// 获取通道
FileChannel inputChannel = fileInputStream.getChannel();
FileChannel outputChannel = fileOutputStream.getChannel();
// 通道不能单独使用,需要配合缓冲区使用
ByteBuffer buffer = ByteBuffer.allocate(1024); //创建非直接缓冲区
//将通道中的数据存入缓冲区中
while (inputChannel.read(buffer) != -1) { // 循环读取
buffer.flip();//更换为读取模式
// 将缓冲区的数据写入通道中
outputChannel.write(buffer);
buffer.clear();//清空缓冲区
}
outputChannel.close();
inputChannel.close();
outputChannel.close();
inputChannel.close();
}
}
通道之间的数据传输:
transferFrom()
? transferTo()
代码:
/**
* 通道之间的传输
* */
@Test
public void channel() throws IOException {
FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("4.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.READ);
// 输入通道 到 输出通道,位置:0开始, 要传输的最大字节数,目标通道
inChannel.transferTo(0,inChannel.size(),outChannel);
outChannel.transferFrom(inChannel,0,inChannel.size());
outChannel.close();
inChannel.close();
}
分散(Scatter)和与聚集(Gather)
分散读取
通道的数据 依次填满到缓冲区中
@Test
public void access() throws IOException {
//创建一个随机访问文件流,以从具有指定名称的文件中读取和写入(可选)。
RandomAccessFile raf = new RandomAccessFile("F:\\01-javaSE\\Vim编辑器基本命令.md", "rw");
// 获取管道
FileChannel channel = raf.getChannel();
// 创建多个缓冲区
ByteBuffer allocate1 = ByteBuffer.allocate(10);
ByteBuffer allocate2 = ByteBuffer.allocate(514);
ByteBuffer allocate3 = ByteBuffer.allocate(1024);
// 分散读取文件
ByteBuffer[] bbs= {allocate1,allocate2,allocate3};
channel.read(bbs);// 读入缓冲区中
//查看缓冲区内容
for (ByteBuffer bb :
bbs) {
bb.flip();//读模式
System.out.println("-----------------------容量为:>"+bb.capacity()+"的内容");
System.out.println(new String(bb.array(),0,bb.limit()));
}
channel.close();
raf.close();
}
输出内容:
-----------------------容量为:>10的内容
# i Vim基
-----------------------容量为:>514的内容
本命令
## vi/vim基本命令表
下面为vi编辑器常用的命令,仅供参考。 相关资料:[http://www.vim.org/docs.php]
vi/vim帮助文档:[http://vimdoc.sourceforge.net/htmldoc/help.html]
| 命令 | 描述 |
| :---------: | :------------------------------------------------------- |
| vi | 从控制台进入vi编辑器 |
| vi filename | 创建名为filename的文件并进入vi?
-----------------------容量为:>1024的内容
?辑器 |
| 命令行模式 | |
| i | 从光标所在字符前插入 |
| a | 从光标所在的字符后插入 |
| o | 从光标所在行的下面插入空白行 |
| I | 从光标所在行的行首插入 |
| A | 从光标所在行的行末插入 |
| O | 从光标所在行的上面插入空白行 |
| s | 删除光标所在字符进入插入模式 |
| S | 删除光标所在行进入插入模式 |
| Esc | 插入模式切换到命令行模式 |
| k | 类似方向键上 |
| j | 类似方向键下
Process finished with exit code 0
聚集写入
按照顺序依次写入通道中
/**
* 聚集写入
* */
@Test
public void Gather() throws IOException {
//创建一个随机访问文件流,以从具有指定名称的文件中读取和写入(可选)。
RandomAccessFile raf = new RandomAccessFile("G:\\Desktop\\shop-1.3.sql", "rw");
// 获取管道
FileChannel channel = raf.getChannel();
// 创建多个缓冲区
ByteBuffer allocate1 = ByteBuffer.allocate(10);
ByteBuffer allocate2 = ByteBuffer.allocate(514);
ByteBuffer allocate3 = ByteBuffer.allocate(1024);
// 分散读取文件
ByteBuffer[] bbs= {allocate1,allocate2,allocate3};
channel.read(bbs);// 读入缓冲区中
for(ByteBuffer bb: bbs){
bb.flip();
System.out.println("----------->容量为:"+bb.capacity()+"缓冲区");
System.out.println(new String(bb.array(),0,bb.limit()));
}
RandomAccessFile rw = new RandomAccessFile("1.sql", "rwd");
//
FileChannel fileChannel = rw.getChannel();
fileChannel.write(bbs);
fileChannel.close();
rw.close();
channel.close();
raf.close();
}
使用 RandomAccessFile rw = new RandomAccessFile("1.sql", "rw"); ,不知道为什么,大部分写入不成功。
操作字符集:charset
- 编码:字符串 -> 字节数组
- 解码:字节数组 -> 字符串
/**
* 字符集
* */
@Test
public void charset(){
Map map = Charset.availableCharsets();//此方法返回的映射对于当前 Java 虚拟机中可用的每个字符集都有一个条目
Set> set = map.entrySet(); // 返回此映射中包含的映射的Set视图
for (Map.Entry entry: set){
System.out.println(entry.getKey()+ "="+entry.getValue());
}
java 可以进行编码和解码的字符集
Big5=Big5
Big5-HKSCS=Big5-HKSCS
CESU-8=CESU-8
EUC-JP=EUC-JP
EUC-KR=EUC-KR
GB18030=GB18030
GB2312=GB2312
GBK=GBK
IBM-Thai=IBM-Thai
IBM00858=IBM00858
......
根据字符集进行编码和解码
/**
* 编码器 -> 编码
* */
@Test
public void charsetCoding() throws CharacterCodingException {
Charset gbk = Charset.forName("GBK"); //获取字符集,进行对应规则编码
CharsetEncoder encoder = gbk.newEncoder(); //为这个字符集构造一个新的编码器
// 字符缓冲区
CharBuffer cb = CharBuffer.allocate(1024);
cb.put("这个一段字符进行编码");
cb.flip(); //读模式,不是读模式无法编码,解码
ByteBuffer bb = encoder.encode(cb); // 进行编码,其实就是转成字节
// 查看编码后的内容
System.out.println("编码------------------》");
for (int i = 0; i < bb.limit(); i++) {
System.out.println(bb.get());
}
bb.flip(); //读模式
// 解码
CharsetDecoder decoder = gbk.newDecoder();//为这个字符集构造一个新的解码器
CharBuffer cbcoder = decoder.decode(bb);
// 查看解码后的内容
System.out.println("解码------------------》");
for (int i = 0; i < cbcoder.limit(); i++) {
System.out.println(cbcoder.get());
}
}
如果字符集和GBK 解码时 UTF-8 就会出现乱码,使用GBK解码就正常显示
网路IO通道
Socket 客户端
ServerScoket 服务端
DatagramSocket 数据报套接字