Java学习笔记--NIO
参考资料:http://ifeve.com/buffers/
BIO/NIO/AIO的区别联系
http://stevex.blog.51cto.com/4300375/1284437
http://www.cnblogs.com/alipayhutu/archive/2012/05/09/2492037.html
1. NIO代码示例
public static void main(String[] args) throws IOException {
RandomAccessFile aFile = new RandomAccessFile("f:\\node.txt","rw");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buf);
while (bytesRead != -1) {
System.out.println("Read,字符数量是:" + bytesRead);
buf.flip();
System.out.println("输出:");
while (buf.hasRemaining()) {
System.out.print((char) buf.get());
}
System.out.println();
buf.clear();
bytesRead = inChannel.read(buf);
}
aFile.close();
}
2. 输出结果:
Read,字符数量是:48
输出:
<node id='-665' lat='38.92025517116' lon='121.58
Read,字符数量是:48
输出:
810979934' />
<node id='-8' lat='38.90686208459
//省略
3. 解释:
3.1 Buffer的分配
要想获得一个Buffer对象首先要进行分配。 每一个Buffer类都有一个allocate方法。下面是一个分配48字节capacity的ByteBuffer的例子。
ByteBuffer buf = ByteBuffer.allocate(48);
这是分配一个可存储1024个字符的CharBuffer:
CharBuffer buf = CharBuffer.allocate(1024);
3.2 向Buffer中写数据
写数据到Buffer有两种方式:
1. 从Channel写到Buffer。例:
buf.put(127);
2. 通过Buffer的put()方法写到Buffer里。例:
int bytesRead = inChannel.read(buf); //read into buffer.
返回值为-1证明读到末尾。put方法有很多版本,允许你以不同的方式把数据写入到Buffer中。例如, 写到一个指定的位置,或者把一个字节数组写入到Buffer。 更多Buffer实现的细节参考JavaDoc。
3.3 flip()方法
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。
从Buffer中读取数据
从Buffer中读取数据有两种方式:
1. 从Buffer读取数据到Channel。例
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);
2. 使用get()方法从Buffer中读取数据。
byte aByte = buf.get();
3.4 clear()与compact()方法
一旦读完Buffer中的数据,需要让Buffer准备好再次被写入。可以通过clear()或compact()方法来完成。
1. clear()
如果调用的是clear()方法,position将被设回0,limit被设置成 capacity的值。换句话说,Buffer 被清空了。Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。
如果Buffer中有一些未读的数据,调用clear()方法,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。
2. compact
如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先先写些数据,那么使用compact()方法。
compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
3.5 mark()与reset()方法
通过调用Buffer.mark()方法,可以标记Buffer中的一个特定position。之后可以通过调用Buffer.reset()方法恢复到这个position
4. Scatter/Gather
4.1 Scattering Reads
Scattering Reads是指数据从一个channel读取到多个buffer中。
代码示例如下:
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
注意buffer首先被插入到数组,然后再将数组作为channel.read() 的输入参数。read()方法按照buffer在数组中的顺序将从channel中读取的数据写入到buffer,当一个buffer被写满后,channel紧接着向另一个buffer中写。
Scattering Reads在移动下一个buffer前,必须填满当前的buffer,这也意味着它不适用于动态消息(译者注:消息大小不固定)。换句话说,如果存在消息头和消息体,消息头必须完成填充(例如 128byte),Scattering Reads才能正常工作。
4.2 Gathering Writes
Gathering Writes是指数据从多个buffer写入到同一个channel。
代码示例如下:
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
//write data into buffers
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);
buffers数组是write()方法的入参,write()方法会按照buffer在数组中的顺序,将数据写入到channel,注意只有position和limit之间的数据才会被写入。因此,如果一个buffer的容量为128byte,但是仅仅包含58byte的数据,那么这58byte的数据将被写入到channel中。因此与Scattering Reads相反,Gathering Writes能较好的处理动态消息。
5. 内存映射 MappedByteBuffer
FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.
a. READ_ONLY,(只读): 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException.(MapMode.READ_ONLY)
b. READ_WRITE(读/写): 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的。 (MapMode.READ_WRITE)
c. PRIVATE(专用): 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本。 (MapMode.PRIVATE)
三个方法:
a. fore();缓冲区是READ_WRITE模式下,此方法对缓冲区内容的修改强行写入文件
b. load()将缓冲区的内容载入内存,并返回该缓冲区的引用
c. isLoaded()如果缓冲区的内容在物理内存中,则返回真,否则返回假
三个特性:
调用信道的map()方法后,即可将文件的某一部分或全部映射到内存中,映射内存缓冲区是个直接缓冲区,继承自ByteBuffer,但相对于ByteBuffer,它有更多的优点:
a. 读取快
b. 写入快
c. 随时随地写入
例:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel; public class MemoryMappedFileInJava {
private static int count = 10485760; // 10 MB
public static void main(String[] args) throws Exception {
RandomAccessFile memoryMappedFile = new RandomAccessFile("f:\\largeFile.txt", "rw");
// Mapping a file into memory
MappedByteBuffer out = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, count);
// Writing into Memory Mapped File
for (int i = 0; i < count; i++) {
out.put((byte) 'A');
}
System.out.println("Writing to Memory Mapped File is completed");
// reading from memory file in Java
for (int i = 0; i < 10; i++) {
System.out.print((char) out.get(i));
}
System.out.println("Reading from Memory Mapped File is completed");
memoryMappedFile.close();
}
}
下面快速总结一下Java内存映射文件和IO
1). Java语言通过java.nio包支持内存映射文件和IO。
2). 内存映射文件用于对性能要求高的系统中,如繁忙的电子交易系统
3). 使用内存映射IO你可以将文件的一部分加载到内存中
4). 如果被请求的页面不在内存中,内存映射文件会导致页面错误
5). 将一个文件区间映射到内存中的能力取决于内存的可寻址范围。在32位机器中,不能超过4GB,即2^32比特。
6). Java中的内存映射文件比流IO要快(译注:对于大文件而言是对的,小文件则未必)
7). 用于加载文件的内存在Java的堆内存之外,存在于共享内存中,允许两个不同进程访问文件。顺便说一下,这依赖于你用的是direct还是non-direct字节缓存。
8). 读写内存映射文件是操作系统来负责的,因此,即使你的Java程序在写入内存后就挂掉了,只要操作系统工作正常,数据就会写入磁盘。
9). Direct字节缓存比non-direct字节缓存性能要好
10). 不要经常调用MappedByteBuffer.force()方法,这个方法强制操作系统将内存中的内容写入硬盘,所以如果你在每次写内存映射文件后都调用force()方法,你就不能真正从内存映射文件中获益,而是跟disk IO差不多。
11). 如果电源故障或者主机瘫痪,有可能内存映射文件还没有写入磁盘,意味着可能会丢失一些关键数据。
12). MappedByteBuffer和文件映射在缓存被GC之前都是有效的。sun.misc.Cleaner可能是清除内存映射文件的唯一选择。
Java学习笔记--NIO的更多相关文章
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
- Java学习笔记(04)
Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...
- 0032 Java学习笔记-类加载机制-初步
JVM虚拟机 Java虚拟机有自己完善的硬件架构(处理器.堆栈.寄存器等)和指令系统 Java虚拟机是一种能运行Java bytecode的虚拟机 JVM并非专属于Java语言,只要生成的编译文件能匹 ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
- 0028 Java学习笔记-面向对象-Lambda表达式
匿名内部类与Lambda表达式示例 下面代码来源于:0027 Java学习笔记-面向对象-(非静态.静态.局部.匿名)内部类 package testpack; public class Test1{ ...
- 0025 Java学习笔记-面向对象-final修饰符、不可变类
final关键字可以用于何处 修饰类:该类不可被继承 修饰变量:该变量一经初始化就不能被重新赋值,即使该值跟初始化的值相同或者指向同一个对象,也不可以 类变量: 实例变量: 形参: 注意可以修饰形参 ...
- Java学习笔记-多线程-创建线程的方式
创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...
随机推荐
- 关于Layouts的分类
ViewGroup ---------------------------------LinearLayout.Relative Layout. AdapterView --------------- ...
- android-UI组件实例大全(六)------ImageView图像视图
图像视图:ImageView 继承view类,用于在屏幕上显示任何Drawable对象,通常用来显示图片: 这里的话我们介绍一些比较常用的属性: Path 1: android:adjustViewB ...
- 2015.9.11模拟赛 codevs 4159【hzwer的迷の数列】
题目描述 Description hzwer找了一个人畜无害的迷の数列…… 现在hzwer希望对这个数列进行一些操作,请你来回答hzwer的问题. 操作一:查询第i个数的大小 操作二:把第i个数的大小 ...
- ASP.NET MVC 3 Razor Nested foreach with if statements
You need to write code this way. @Html.Raw("<tr>") Copy the below code and paste it ...
- 数据加密算法---base64
简介 base64是把8位字符打散,转换成不被人直接识别的形式,严格来说它并不是加密算法,只能算做一种编码方式 原理 首先准备64个字符数组做为“数组库” ['A', 'B', 'C', ... 'a ...
- 如何解决ajax跨域问题
如何解决ajax跨域问题(转) 由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的跨域问题 ...
- SpringMVC 拦截器(interceptors)对样式(css),JavaScript(js),图片(images)链接的拦截
因为在web.xml配置了 <servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pa ...
- 3DES加密算法
在日常设计及开发中,为确保数据传输和数据存储的安全,可通过特定的算法,将数据明文加密成复杂的密文.目前主流加密手段大致可分为单向加密和双向加密. 单向加密:通过对数据进行摘要计算生成密文,密文不可逆推 ...
- 2.x最终照着教程,成功使用OpenGL ES 绘制纹理贴图,添加了灰度图
在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理. 学校时候不知道OpenGL的重要性,怕晦涩的语法.没有跟老师学习OpenGL的环境配置,现在仅仅能利用coco ...
- tail-head
[root@rusky]# tail test3 #不加参数默认显示全部内容 line line2 line3 line4 line5 line6 line7 line8 line9 line10 [ ...