Buffer
Buffer
我们用原有 IO 读写文件应该不会陌生了,顺带回顾一下,大致两种:
1. 在 InputStream 或 OutputStream 上读写字节或字节数组,读 InputStream 时用是否返回 -1 来判断是否到达末尾。
2. 包装成 Reader/Writer 可以直接读写字符串,进一步包装到 BufferedReader/BufferedWriter 就可以按行读写了。readLine() 时看是否返回 null 断定是否读完了最后一行。
现在我们要用 NIO 来读写文件,肯定是要用到 Channel 和 Buffer 了。一句话描述过程就是从 FileInputStream 得到的 FileChannel 中读取数据到 Buffer 中,再处理 Buffer 中的数据。看代码:
- public static void main(String[] args) throws Exception {
- FileInputStream fis = new FileInputStream("C:/Java/jdk1.6.0_18/LICENSE");
- // 得到文件通道
- FileChannel fc = fis.getChannel();
- // 分配与文件尺寸等大的缓冲区
- ByteBuffer bf = ByteBuffer.allocate((int) fc.size());
- // 整个文件内容全读入缓冲区,即是内存映射文件
- fc.read(bf);
- // 把缓冲中当前位置回复为零
- bf.rewind();
- // 输出缓冲区中的内容
- while (bf.hasRemaining()) {
- System.out.print((char) bf.get());
- }
上面程序使用了一个与文件尺寸等大的缓冲区,正好能一次性把文件内容全部读入内存,如果文件过多将是十分耗费的内存的,所以我们可能须手工指定某个大小(如 1024,2048) 的缓冲区,然后分多次读入文件内容到缓冲区中。这时候程序就是下面那样子了:
- public static void main(String[] args) throws Exception {
- FileInputStream fis = new FileInputStream("C:/Java/jdk1.6.0_18/LICENSE");
- // 得到文件通道
- FileChannel fc = fis.getChannel();
- // 指定大小为 1024 的缓冲区
- ByteBuffer bf = ByteBuffer.allocate(1024);
- // 读取通道中的下一块数据到缓冲区中
- // 缓冲区的 position 即为当前缓冲区中最后有效位置
- while (fc.read(bf) != -1) {
- // 把缓冲中当前位置回复为零,前把缓冲区的 limit 设置为之前 position 值
- bf.flip();
- // 输出缓冲区中的内容
- while (bf.hasRemaining()) {
- System.out.print((char) bf.get());
- }
- // 清理缓冲区,准备再次读取数据
- bf.clear();
- }
- }
留意对缓冲区的 rewind()/flip()/clear() 操作所产生的影响,即对 position/limit/mark 等标志的影响。
最后提醒操作完之后,要关闭通道和输入流。
再来看看 NIO 怎么写文件
- private static final int SIZE = 1024;
- public static void main(String[] args) throws FileNotFoundException,
- IOException {
- FileOutputStream fos = new FileOutputStream("c:/nio.txt");
- // 得到文件通道
- FileChannel fc = fos.getChannel();
- // 指定大小为 1024 的缓冲区
- ByteBuffer bf = ByteBuffer.allocate(1024);
- // 要写入文件的字符串
- String greeting = "Hello, Java NIO";
- // 把以上字符串逐字放入缓冲区
- for (int i = 0; i < greeting.length(); i++) {
- bf.putChar(greeting.charAt(i));
- }
- // 记得执行这个方法,使得 position=0, limit=30, 才能写入正确的数据
- // 否则 position 为 30, limit 为 1024,将会把 30 之后的全部空数据(0) 填到文件中
- bf.flip();
- // 缓冲区数据写入到文件中,会把缓冲区中从 position 到 limit 之间的数据写入文件
- fc.write(bf);
- fc.close(); // 关闭文件通道
- fos.close(); // 关闭文件输出流
- }
同样的,如果是写入中文内容,也需要进行字符集的相关处理。执行后在 C 盘根目录下产生 nio.tst 文件,内容就是 Hello, Java NIO。此代码的关键之处就是对缓冲的 flip() 调用,你可以在调试模式下观察到 flip() 方法调用前后,缓冲区 bf 的 position/limit 属性的变化。试着注释掉 flip() 代码,看看两次生成的 nio.tst 文件内容是不是大相径庭。
所以,要用好 NIO,缓冲区的 mark/position/limit/capacity 属性应理解,以及 clear()/flip()/rewind() 分别会怎么影响到以上属性。
还有,虽然说通道是双向的,字面上不像流那样区分输入通道或是输出通道,但实际通道也存在只读或只写的特性,例如由 FileInputStream.getChannel() 获得的通道是无法写入内容的,由 FileOutputStream.getChannel() 获得的通道是不能读的,否则会抛出相应的异常 NonWritableChannelException 和 NonReadableChannelException。而且 Buffer 也存在着是否只读的属性。
前面的代码在这里只是说明用 NIO 读写文件应如何处理,并不是说比起用旧 IO 流式的写法效率就更高了。NIO 的高效率只会体现在有些时候,并非任何时候都优于旧 IO,那是块操作和字节操作的区别,用 NIO 时要小心内存。伸手就能摘到的梨用不着搬个凳子,何况旧 IO 实现起来还更简洁些呢! (文/隔叶黄莺)
转自: http://www.360doc.com/content/12/0515/11/1542811_211144310.shtml
Buffer的更多相关文章
- Node.js:Buffer浅谈
Javascript在客户端对于unicode编码的数据操作支持非常友好,但是对二进制数据的处理就不尽人意.Node.js为了能够处理二进制数据或非unicode编码的数据,便设计了Buffer类,该 ...
- java.IO输入输出流:过滤流:buffer流和data流
java.io使用了适配器模式装饰模式等设计模式来解决字符流的套接和输入输出问题. 字节流只能一次处理一个字节,为了更方便的操作数据,便加入了套接流. 问题引入:缓冲流为什么比普通的文件字节流效率高? ...
- 一点公益商城开发系统模式Ring Buffer+
一个队列如果只生产不消费肯定不行的,那么如何及时消费Ring Buffer的数据呢?简单的方案就是当Ring Buffer"写满"的时候一次性将数据"消费"掉. ...
- CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总
CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总 开始 总的来说,OpenGL应用开发者会遇到为如下三种数据创建Vertex Buffer Object的情形: ...
- golang bytes.Buffer Reset
func t() { a := []'} buf := new(bytes.Buffer) buf.Write(a) b := buf.Bytes() fmt.Println(b) buf.Reset ...
- 使用Ring Buffer构建高性能的文件写入程序
最近常收到SOD框架的朋友报告的SOD的SQL日志功能报错:文件句柄丢失.经过分析得知,这些朋友使用SOD框架开发了访问量比较大的系统,由于忘记关闭SQL日志功能所以出现了很高频率的日志写入操作,从而 ...
- directx12中vetex buffer、index buffer和constant buffer绑定piple line的时机
类别 时机 函数 建Heap vetex buffer 在Draw函数中 ID3D12GraphicsCommandList::IASetVertexBuffer 否 index buffer 在Dr ...
- JAVA NIO Buffer
所谓的输入,输出,就是把数据移除或移入缓冲区. 硬件不能直接访问用户控件(JVM). 基于存储的硬件设备操控的是固定大小的数据块儿,用户请求的是任意大小的或非对齐的数据块儿. 虚拟内存:使用虚 ...
- Circular Buffer
From:http://bradforj287.blogspot.com/2010/11/efficient-circular-buffer-in-java.html import java.util ...
- Buffer类
输入流中可以通过缓冲区来加大读取的效率,sun公司感觉可以加快执行效率,他就为我们提供了一个类来操作缓存区. Buffer来头的类:所有缓冲流都是以Buffer开头的: 学习缓冲流的作用: Buffe ...
随机推荐
- CSS3 媒体记
css3 媒体 Media Type 媒体类型 媒体类型是CSS2中一个非常有用的属性.通过媒体类型可以对不同的设备指定不同的样式. W3C共列出十种媒体类型,如表: 值 设备类型 all 所有设备 ...
- IE9+浏览器input文本框/密码框后面的小叉子/小眼睛清除
为了方便我们的触控操作,IE高等浏览器针对input及input type="password"分别提供了快速清除钮(X图标)以及密码文字显示钮(小眼睛图标)的功能. 由于这经常跟 ...
- 参数请求post, get , delete中的基本使用(2)
UTF-8数字编码 /// <summary> /// 参数的Url请求 /// </summary> /// <returns></returns> ...
- struts2-权限拦截器、日志拦截器、execAndWait(进度条)拦截器配置
1.权限拦截器 package login; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.Serv ...
- OC10_文件练习
// // TextHander.h // OC10_文件练习 // // Created by zhangxueming on 15/6/19. // Copyright (c) 2015年 zha ...
- Php 输出语句
输出语句 echo 示例: print(); 示例: 只能输出标量数据类型,无法输出布尔false print_r(); print_r可以以比较容易理解的方式显示数据 示例: var_dump(); ...
- [Guava学习笔记]Basic Utilities: Null, 前置条件, Object方法, 排序, 异常
我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3842433.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...
- JSON的使用
最近在项目中大量的使用了JSON, 发现JSON和XML的功能相近,都是一种数据传输格式.只是与XML相比JSON显得更加轻量级,使用也更加容易. JSON依赖的第三方jar包: commons-be ...
- Poj OpenJudge 百练 1573 Robot Motion
1.Link: http://poj.org/problem?id=1573 http://bailian.openjudge.cn/practice/1573/ 2.Content: Robot M ...
- 对于观察者模式,Reactor模式,Proactor模式的一点理解
最近就服务器程序IO效率这一块了解一下设计模式中的Reacotr模式和proactor模式,感觉跟观察者模式有些类似的地方,网上也看了一些其他人对三者之间区别的理解,都讲得很仔细,在此根据自己的理解做 ...