1.前言

这一篇随笔是写 NIO 关于文件输入输出的总结

/*
总结:
1.io操作包括 socket io ,file io ;
2.在nio模型,file io使用fileChannel 管道 ,socket io 使用socketChannel管道,
3.在file io可以使用transferTo 或 transferFrom 实现管道向管道的的数据传输,但是别人说有可能传输数据不完成,不建议这样做;
4.GBK 为2 byte,如果是utf-8,最大长度是4字节 ,是可变的,需要循环判断获取字节长度后设置limit值才能获取完成的utf-8编码,否则会乱码,
5. buffer.compact();将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样
,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。也就是说把已经写入缓冲区但是还没有读的数据左移到开头,
然后将position设为该数据默认然后继续做写操作,不会覆盖这些数据
6. buffer.clear();调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,
只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,
意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
7. buffer.flip();重置position,limit,capacity, 也就是limit= position,position=0,capacity=设好的最大值,
8. buffer.position();缓冲区的有定位位置 ,一般是position值小于limit值,否则无数据
9. buffer.limit(); 缓冲区的有限制位置 ,一般是position值小于limit值,否则无数据
10. 不论是读取还是写入,都是position 于limit之间的位置操作
11. buffer.capacity();缓冲区的最大容量 ,由ByteBuffer.allocate(【int】) 设置
12. buffer.hasRemaining();是否还有有效数据 ,即position值小于limit值
13.buffer缓冲区内部是字节流,使用buffer.array()从 缓冲区获取position 于limit之间的底层字节数组,然后使用 new String将字节数组转字符串
*/

2.操作

(1)把字符串写入文件[使用 buffer.put]

    /**
* 把字符串写入文件[使用 buffer.put]
*/
@Test
public void w1() {
try {
//=================================
// //new文件对象
// File file = new File("C:/Users/cen/Desktop/ww/", "write.txt");
// //字节输出流,意思是指JVM的内容输出到文件对象里面
// //如果文件存在 覆盖
// FileOutputStream fos = new FileOutputStream(file);
//
//上面几句等同于下面一句
FileOutputStream fos = new FileOutputStream("C:/Users/cen/Desktop/ww/write.txt");
//==============================================
//true表示追加,如果文件存在 向里面继续添加内容,不加默认是覆盖
// FileOutputStream fos=new FileOutputStream(file,true);
//获取通道,该通道允许写操作【根据字节流是输入还是输出决定是读通道还是写通道】
FileChannel fc = fos.getChannel();
//
// System.out.println("通道数量====" + fc.size());
//打印的结果是0
//
//allocate是使用JVM的的内存的,适合小文件;allocateDirect则是使用系统的内存的,适合大文件
//设置字节缓的大小
ByteBuffer buffer = ByteBuffer.allocate(1024);
// ByteBuffer.allocateDirect()
//控制台写入字符串
// Scanner sca = new Scanner(System.in);
// String str = sca.next();
// \n 转行符算是一个字符
String str = "sa34523ui2345672\n" +
"kkkkuuuushfjsdhjkfhs222333444555\n" +
"撒大噶和\n" +
"稍等哈肯定会介绍的几款圣诞卡十大科技";
//将字符串转成字节后,放入字节缓冲
buffer.put(str.getBytes(StandardCharsets.UTF_8));
// 此行语句一定要有,每次执行了这一句才可以做io操作
buffer.flip();
//通道对字节缓冲区里的内容写入文件对象里面
fc.write(buffer);
System.out.println("写入成功");
//清空缓冲块
buffer.clear();
//关闭管道
fc.close();
//关闭字节输出流
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}

(2)把字符串写入文件[使用 ByteBuffer.wrap ,不设置缓冲区大小]

    /**
* 把字符串写入文件[使用 ByteBuffer.wrap ,不设置缓冲区大小]
*
* @throws Exception
*/
@Test
public void w2() throws Exception {
// 构造一个传统的文件输出流
FileOutputStream out = new FileOutputStream("C:/Users/cen/Desktop/ww/write.txt");
// 通过文件输出流获取到对应的FileChannel,以NIO的方式来写文件
FileChannel channel = out.getChannel();
// 将数据写入到Buffer中
ByteBuffer buffer = ByteBuffer.wrap("hello world".getBytes());
// 通过FileChannel管道将Buffer中的数据写到输出流中去,持久化到磁盘中去
channel.write(buffer);
channel.close();
out.close();
}

(3)从文件中一次性读取字符串

 /**
* 从文件中一次性读取字符串
*/
public static void main(String[] args) throws Exception {
//==============================================
//new文件对象
File file = new File("C:/Users/cen/Desktop/ww/write2.txt");
//字节输入流
//意思是文件内容向JVM输入
FileInputStream fis = new FileInputStream(file);
//
//上面几句等同于下面一句
// FileInputStream fis = new FileInputStream("C:/Users/cen/Desktop/ww/write.txt");
//==============================================
//
//开启管道
FileChannel fc = fis.getChannel();
//设置字节缓冲区的大小,这里设为文件对象的字节长度
// ByteBuffer buffer = ByteBuffer.allocate((int) file.length());
ByteBuffer buffer = ByteBuffer.allocate(1024);
//管道将文件对象的内容读出并放入缓冲区里面,字符上限为上面缓冲区设置的最大值
//read()方法返回的是个抽象的整数,意为字符的长度/个数,当为空时返回-1
int nread = fc.read(buffer);
// System.out.println(buffer);
System.out.println("抽象整数==" + nread);
// buffer.array()是缓冲区获取底层byte[]数组,
// 然后使用 new String 将字节转成字符串
System.out.println(new String(buffer.array()));
//清除缓冲区
buffer.clear();
//关闭管道
fc.close();
//关闭字节输入流
fis.close(); }

(4)多次读取文件数据--解决utf-8中文乱码问题

 /**
* 多次读取文件数据--解决utf-8中文乱码问题
*/
@Test
public void readutf8Data() throws Exception {
//==============================================
//new文件对象
File file = new File("C:/Users/cen/Desktop/ww/write.txt");
//字节输入流
//意思是文件内容向JVM输入
FileInputStream fis = new FileInputStream(file);
//==============================================
//
//开启管道
FileChannel fc = fis.getChannel();
//如果设置太小的,会乱码【解决方式不靠谱】
//如果是utf-8,最大长度是4字节 ,GBK 为2 byte
//因此这里设置最小是4
ByteBuffer buffer = ByteBuffer.allocate(6);
//管道将文件对象的内容读出并放入缓冲区里面,字符上限为上面缓冲区设置的最大值
//read()方法返回的是个抽象的整数,意为字符的长度/个数,当为空时返回-1
int mread;
//此时管道读取数据放入缓冲,缓冲的定位position 不再是0 ,需要将limit设为position,而position需要恢复到0 ,
//形成 【 limit == 当前的position值【也等于mread】,position == 0 , cap 不变】
while ((mread = fc.read(buffer)) != -1) { byte b;
//计算出此时中文utf-8的编码长度后放入这里
int idx; //out可以bai改成任何不与保留关键字相同的字符,其中du标签out代表了这个for循环结构zhi体。理论上,标签可以标记任何结构体
//break out ;代表语句执行跳出整个for循环结构
out:
for (idx = buffer.position() - 1; idx >= 0; idx--) {
b = buffer.get(idx);
if ((b & 0xff) >> 7 == 0) { // 0xxxxxxx
break;
} if ((b & 0xff & 0xc0) == 0xc0) { // 11xxxxxx,110xxxxx、1110xxxx、11110xxx
idx -= 1;
break;
}
if ((b & 0xff & 0x80) == 0x80) {
for (int i = 1; i < 4; i++) {
b = buffer.get(idx - i);
if ((b & 0xff & 0xc0) == 0xc0) {
if ((b & 0xff) >> (5 + 1 - i) == 0xf >> (3 - i)) {
//break out ;代表语句执行跳出整个for循环结构
break out;
} else {
idx = idx - 1 - i;
//break out ;代表语句执行跳出整个for循环结构
break out;
}
}
}
}
} //缓冲区定位参数移位
buffer.flip();
//获取限制数,备份
int limit = buffer.limit();
//设限制数为上面计算出的utf-8字符的长度
buffer.limit(idx + 1); // 阻止读取跨界数据
//
System.out.println(Charset.forName("UTF-8").decode(buffer).toString());
// 恢复limit
buffer.limit(limit);
//compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。
// limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
//也就是说把已经写入缓冲区但是还没有读的数据左移到开头,然后将position设为该数据默认
//然后继续做写操作,不会覆盖这些数据
buffer.compact();
}
//清除缓冲区
buffer.clear();
//关闭管道
fc.close();
//关闭字节输入流
fis.close();
}

(5) 文件复制 【如果已经存在则覆盖,因此需要提前判断是否存在】

  /**
* 文件复制 【如果已经存在则覆盖,因此需要提前判断是否存在】
*/
@Test
public void copyFile() throws Exception {
//分别创建流
//字节输入流,用于从文件读取数据,即原地址文件【被拷贝的文件】
FileInputStream fis = new FileInputStream("C:/Users/cen/Desktop/ww/write.txt");
//字节输出流,用于从将数据输出到文件里,即目标地址文件【拷贝文件】
FileOutputStream fos = new FileOutputStream("C:/Users/cen/Desktop/ww/write_copy.txt");
//
//分别开启通道
FileChannel sourceFC = fis.getChannel();
FileChannel destFC = fos.getChannel();
//
//复制 【一个主动一个被动】
//从哪里转移到这里 【参数 0 ,其实是管道的数量,等同于 destFC.size()】
destFC.transferFrom(sourceFC, 0, sourceFC.size());
//从这里转移到哪里
// sourceFC.transferTo(destFC,0,sourceFC.size());
//
//关闭通道
sourceFC.close();
destFC.close();
//
// 关闭字节输入流
fis.close();
fos.close(); }

NIO【同步非阻塞io模型】关于 文件io 的总结的更多相关文章

  1. Java NIO 同步非阻塞

    同步非阻塞IO (NIO) NIO是基于事件驱动思想的,实现上通常采用Reactor(http://en.wikipedia.org/wiki/Reactor_pattern)模式,从程序角度而言,当 ...

  2. NIO【同步非阻塞io模型】关于 NIO socket 的详细总结【Java客户端+Java服务端 + 业务层】【可以客户端间发消息】

    1.前言 以前使用 websocket来实现双向通信,如今深入了解了 NIO 同步非阻塞io模型 , 优势是 处理效率很高,吞吐量巨大,能很快处理大文件,不仅可以 做 文件io操作, 还可以做sock ...

  3. 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?

    原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...

  4. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  5. java的高并发IO原理,阻塞BIO同步非阻塞NIO,异步非阻塞AIO

    原文地址: IO读写的基础原理 大家知道,用户程序进行IO的读写,依赖于底层的IO读写,基本上会用到底层的read&write两大系统调用.在不同的操作系统中,IO读写的系统调用的名称可能不完 ...

  6. IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)

    同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...

  7. 同步异步阻塞非阻塞Reactor模式和Proactor模式 (目前JAVA的NIO就属于同步非阻塞IO)

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...

  8. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程 并行与并发 同步与异步 阻塞与非阻塞 CPU密集型与IO密集型 线程与进程 进 ...

  9. Socket-IO 系列(三)基于 NIO 的同步非阻塞式编程

    Socket-IO 系列(三)基于 NIO 的同步非阻塞式编程 缓冲区(Buffer) 用于存储数据 通道(Channel) 用于传输数据 多路复用器(Selector) 用于轮询 Channel 状 ...

  10. IO同步阻塞与同步非阻塞

    BIO.NIO.AIO IO(BIO)和NIO区别:其本质就是阻塞和非阻塞的区别 阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,就会一直等待,直到传输完毕为止. 非阻塞概念:应用程序直 ...

随机推荐

  1. 走进Spring Boot源码学习之路和浅谈入门

    Spring Boot浅聊入门 **本人博客网站 **IT小神 www.itxiaoshen.com Spring Boot官网地址:https://spring.io/projects/spring ...

  2. 第三届“传智杯”全国大学生IT技能大赛(初赛A组)题解

    留念 C - 志愿者 排序..按照题目规则说的排就可以.wa了两发我太菜了qwq #include<bits/stdc++.h> using namespace std; const in ...

  3. Sentinel之流控规则

    在上文Sentinel流量防卫兵中讲到了Sentinel入门以及流控规则一小部分,而Sentinel还有以下规则: 熔断降级规则 热点参数规则 系统规则 黑白名单规则 本文要讲的是流控规则 流量控制规 ...

  4. 二级C复习

    二级C语言 队列 计算队列中元素个数 种 : rear > front ,直接减 第二种: rear < front 上面两种综合一起,求元素个数公式 :(r - f + maxsize) ...

  5. OAuth2.0实战:认证、资源服务异常自定义!

    大家好,我是不才陈某~ 这是<Spring Security 进阶>的第4篇文章,往期文章如下: 实战!Spring Boot Security+JWT前后端分离架构登录认证! 妹子始终没 ...

  6. Redis主从 部署和配置

    目录 一.主从简介 主从介绍 主从原理 二.主从部署 环境介绍 主从配置 临时主从 三.主从测试 一.主从简介 主从介绍 Redis都是主节点.每个从节点只能有一个主节点,而主节点可以同时具有多个从节 ...

  7. Redis慢查询配置和优化

    目录 一.介绍 二.参数配置 sql动态配置 配置文件设置 三.sql操作 四.优化 一.介绍 慢查询只记录redis执行时间,并不记录redis服务到客户端之间的网络问题. 超过多少毫秒的才被记录 ...

  8. 编译工具sbt部署

    目录 一.简介 二.部署 三.测试 一.简介 项目构建工具是项目开发中非常重要的一个部分,充分利用好它能够极大的提高项目开发的效率.在学习SCALA的过程中,我遇到了SBT(Simple Build ...

  9. 【web】php文件包含(利用phpinfo)

    Docker搭建复现环境 地址:https://github.com/vulhub/vulhub/tree/master/php/inclusion ps. github单独下载一个文件夹的方法: 安 ...

  10. bootstrap.css 进度条没有动画效果

    操作系统设置会影响浏览器的行为 Win+R 输入 sysdm.cpl ,3 打开 性能 的 设置 确保 窗口内动画控件和元素 被勾选