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. python自带性能强悍的标准库 itertools

    可迭代对象就像密闭容器里的水,有货倒不出 itertools是python内置的标准模块,提供了很多简洁又高效的专用功能,使用得当能够极大的简化代码行数,同时所有方法都是实现了生成器函数,这就意味着极 ...

  2. 30个类手写Spring核心原理之AOP代码织入(5)

    本文节选自<Spring 5核心原理> 前面我们已经完成了Spring IoC.DI.MVC三大核心模块的功能,并保证了功能可用.接下来要完成Spring的另一个核心模块-AOP,这也是最 ...

  3. 如何用CodeBlocks调试?

    一.简介 这篇文章我主要会介绍CodeBlocks的调试功能,并简单讲述如何使用它. 二.前言 大家好,最近和小伙伴们讨论修改程序的时候,我突然想到,授人以鱼不如授人以渔(指调试),于是这篇文章应运而 ...

  4. DevOps的分与合

    一.抽象的 DevOps DevOps 是使软件开发和 IT 团队之间的流程自动化的一组实践,以便他们可以更快,更可靠地构建,测试和发布软件.DevOps 的概念建立在建立团队之间协作文化的基础上,这 ...

  5. 祭出“成本”列(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 今天开始成本. 张同学说,成本就是balabalabala-- 好吧,本妖向来不会背名词解释,不过有些公式还是需要背一下下 ...

  6. CF1036A Function Height 题解

    Content 给定一个坐标系,在它的 \(x\) 轴上有 \(2n+1\) 个点 \(P_0,P_1,P_2,...,P_{2n}\),其中对于 \(0\leqslant i\leqslant 2n ...

  7. CF1077A Frog Jumping 题解

    Content 在一个数轴上有一个动点,初始时在 \(0\) 这个位置上,接下来有若干次操作,对于第 \(i\) 次操作: 如果 \(i\) 是奇数,那么动点往右移 \(a\) 个单位. 如果 \(i ...

  8. CF1141C Polycarp Restores Permutation 题解

    Content 给定一个长度为 \(n-1\) 的序列 \(q\),问你是否能找到一个 \(1\sim n\) 的排列 \(p\),使得 \(\forall i\in[1,n)\),\(q_i=p_{ ...

  9. microsoft project 出现不能保存为xls文件时可以按照如下方法解决

    工具->选项->安全性

  10. SQL:利用多表更新优化子查询

    原SQL: update bi_data.order_list_wxset is_start='1',proc_time=now()where 1=1and is_end='0' and 交易时间&l ...