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的更多相关文章

  1. Node.js:Buffer浅谈

    Javascript在客户端对于unicode编码的数据操作支持非常友好,但是对二进制数据的处理就不尽人意.Node.js为了能够处理二进制数据或非unicode编码的数据,便设计了Buffer类,该 ...

  2. java.IO输入输出流:过滤流:buffer流和data流

    java.io使用了适配器模式装饰模式等设计模式来解决字符流的套接和输入输出问题. 字节流只能一次处理一个字节,为了更方便的操作数据,便加入了套接流. 问题引入:缓冲流为什么比普通的文件字节流效率高? ...

  3. 一点公益商城开发系统模式Ring Buffer+

    一个队列如果只生产不消费肯定不行的,那么如何及时消费Ring Buffer的数据呢?简单的方案就是当Ring Buffer"写满"的时候一次性将数据"消费"掉. ...

  4. CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总

    CSharpGL(38)带初始数据创建Vertex Buffer Object的情形汇总 开始 总的来说,OpenGL应用开发者会遇到为如下三种数据创建Vertex Buffer Object的情形: ...

  5. golang bytes.Buffer Reset

    func t() { a := []'} buf := new(bytes.Buffer) buf.Write(a) b := buf.Bytes() fmt.Println(b) buf.Reset ...

  6. 使用Ring Buffer构建高性能的文件写入程序

    最近常收到SOD框架的朋友报告的SOD的SQL日志功能报错:文件句柄丢失.经过分析得知,这些朋友使用SOD框架开发了访问量比较大的系统,由于忘记关闭SQL日志功能所以出现了很高频率的日志写入操作,从而 ...

  7. directx12中vetex buffer、index buffer和constant buffer绑定piple line的时机

    类别 时机 函数 建Heap vetex buffer 在Draw函数中 ID3D12GraphicsCommandList::IASetVertexBuffer 否 index buffer 在Dr ...

  8. JAVA NIO Buffer

    所谓的输入,输出,就是把数据移除或移入缓冲区.   硬件不能直接访问用户控件(JVM). 基于存储的硬件设备操控的是固定大小的数据块儿,用户请求的是任意大小的或非对齐的数据块儿.   虚拟内存:使用虚 ...

  9. Circular Buffer

    From:http://bradforj287.blogspot.com/2010/11/efficient-circular-buffer-in-java.html import java.util ...

  10. Buffer类

    输入流中可以通过缓冲区来加大读取的效率,sun公司感觉可以加快执行效率,他就为我们提供了一个类来操作缓存区. Buffer来头的类:所有缓冲流都是以Buffer开头的: 学习缓冲流的作用: Buffe ...

随机推荐

  1. 【解决】应用程序无法正常启动(0xc000007b)。请单击“确定”关闭应用程序。

    换了SSD硬盘,装了Windows 7 SP1 x64的系统.用了一段时间,突然一天有些软件打不开了.弹出下面的提示 应用程序无法正常启动(0xc000007b).请单击“确定”关闭应用程序.第一时间 ...

  2. C#数组比较取值

    string strs = string.Empty;            string[] strArray1 = { "a", "b", "c& ...

  3. winform 上传文件

    using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO ...

  4. 如何同时启动多个Tomcat服务器

    1.使用压缩版的tomcat不能使用安装版的. 2.第一个tomcat的配置不变. 3.增加环境变量CATALINA_HOME2,值为新的tomcat的地址:增加环境变量CATALINA_BASE2, ...

  5. Eclipse Code Templates设置

    从工作开始,经历了几个项目的开发,现在的项目一般都是一个团队共同开发,而每个人都有自己的编码习惯,为了统一格式,项目组在项目开发之前都会制定一系列的规范.俗话说约定优于配置,但是在执行过程中往往发现效 ...

  6. select2 取值 赋值

    项目中心引入了select2的插件.优势:可以多选.搜索,缺点:存取值不如select方便. select2 取值: <script type="text/javascript&quo ...

  7. InnoDB 离线转储工具

    一,应用场景; 1,表空间严重损坏,无法恢复;2,数据库表空间文件丢失后从磁盘上打捞出部分数据页面;3,恢复删除记录; 二,功能; 从数据页中直接转储出文本格式的行数据,从而可以后期用 LOAD DA ...

  8. TIMAC 学习笔记(二)

    昨天大体上熟悉了TIMAC自带的CC2530的示范例程,今天先从演示抓包入手,分析四种不同的配置工程在空中传输的差异.随后,会按照扫描.组网.入网等MAC层接口函数入手,结合IEEE 802.15.4 ...

  9. 隐藏index.php - ThinkPHP完全开发手册 - 3.1

      为了更好的实现SEO优化,我们需要隐藏URL地址中的index.php,由于不同的服务器环境配置方法区别较大,apache环境下面的配置我们可以参考5.9 URL重写来实现,就不再多说了,这里大概 ...

  10. TweenMax动画库学习(五)

    目录            TweenMax动画库学习(一)            TweenMax动画库学习(二)            TweenMax动画库学习(三)            Tw ...