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. ActiveMQ(三)——理解和掌握JMS(1)

    一.JMS基本概念 JMS是什么JMS Java Message Service,Java消息服务,是JavaEE中的一个技术. JMS规范JMS定义了Java中访问消息中间件的接囗,并没有给予实现, ...

  2. 【Spark】【复习】Spark入门考前概念相关题复习

    Spark考前概念相关题复习 AUthor:萌狼蓝天 哔哩哔哩:萌狼蓝天 博客园:我的文章 - 萌狼蓝天 博客:萌狼工作室 - 萌狼蓝天 (mllt.cc) 选择题 Hadoop 1.HADOOP的三 ...

  3. git push大文件失败(write error: Broken pipe)完美解决

    问题 在使用git push推送大文件(超过了100MB)到GitHub远程仓库时提示异常,异常信息如下: fatal: sha1 file '<stdout>' write error: ...

  4. 可落地的DDD代码实践

    目录 前言 一.从六边形架构谈起 二.依赖倒置 三.DDD 代码分层 3.1 用户接口层 3.2 应用层 3.2 1 Response vs Exception 3.2.2 CQE vs DTO 3. ...

  5. C# 编写一个小巧快速的 Windows 动态桌面软件

    开源自己前段时间使用 C# 编写的 Windows 动态桌面软件,在接下来的博客我将描写一些技术细节和遇到的一些坑.这个软件可以把视频设置成桌面背景播放,不仅如此而且还可以把网页或一个网页文件设置成桌 ...

  6. Python把两个列表索引相同的值相加

    方案一 list1=[1,2,3,4,5] list2=[6,7,8,9,10] list3=[] list3=[i + j for i, j in zip(list1, list2)] print( ...

  7. MySQL查询数据库表空间大小

    一.查询所有数据库占用空间大小 SELECT TABLE_SCHEMA, CONCAT( TRUNCATE(SUM(data_length) / 1024 / 1024, 2), ' MB' ) AS ...

  8. [BUUCTF]REVERSE——[FlareOn4]IgniteMe

    [FlareOn4]IgniteMe 附件 步骤: 例行检查,32位程序,无壳 32位ida载入 当满足第10行的if条件时,输出G00d j0b!提示我们成功,看一下sub_401050函数 3.s ...

  9. CF975A Aramic script 题解

    Content 定义一个字符串的根为字符串中不同种类的字符按字典序非降序排列得到的字符串.例如 \(\texttt{aaa}\) 的词根为 \(\texttt{a}\),\(\texttt{babb} ...

  10. CF1059A Cashier 题解

    Content 定义一天长度为 \(L\),每次休息的时间为 \(a\).一天会有 \(n\) 个客人到访,第 \(i\) 个客人会在 \(t_i\) 的时刻到访,会停留 \(l_i\) 的时间.只有 ...