NIO里对性能提升最显著的是内存映射(memory mapping),内存访问的速度往往比文件访问的速度快几个数量级。

  在内存映射之前,还需要看NIO的一些其他的特性。

 缓冲区分片

  slice()方法根据现有的缓冲区创建一个子缓冲区。也就是说,它创建一个新的缓冲区,新缓冲区与原来的缓冲区的一部分共享数据。 

package nio;

import java.nio.ByteBuffer;

public class SliceTest {

    public static void main(String [ ] args) {
ByteBuffer buffer = ByteBuffer.allocate( 10 );
for (int i=0; i<buffer.capacity(); ++i) {
buffer.put( (byte)i );
}
buffer.position( 3 );
buffer.limit( 7 );
ByteBuffer slice = buffer.slice(); System.out.println("slice contains: ");
while (slice.remaining()>0) {
System.out.println(slice.get() );
} for (int i=0; i<slice.capacity(); ++i) {
byte b = slice.get( i );
b *= 11;
slice.put( i, b );
}
System.out.println("================");
buffer.position( 0 );
buffer.limit( buffer.capacity() ); while (buffer.remaining()>0) {
System.out.println( buffer.get() );
} } }

  输出结果为:

slice contains:
3
4
5
6
================
0
1
2
33
44
55
66
7
8
9

 分散和聚集

  一个分散的读取就像一个常规通道读取,只不过它是将数据读到一个缓冲区数组中而不是读到单个缓冲区中。同样地,一个聚集写入是向缓冲区数组而不是向 单个缓冲区写入数据。

  你可能在编写一个使用消息对象的网络应用程序,每一个消息被划分为固定长度的头部和固定长度的正文。您可以创建一个刚好可以容纳头部的缓冲区和另一个刚好可以容难正文的缓冲区。当您将它们放入一个数组中并使用分散读取来向它们读入消息时,头部和正文将整齐地划分到这两个缓冲区中。一个缓冲区读完后,剩余的数据会依次读入剩余的缓冲区中。

ByteBuffer header = ByteBuffer.allocate (32);
ByteBuffer body = ByteBuffer (640 * 480);
fileChannel.read (header);
fileChannel.read (body);

  大多数NIO通道支持分散/聚集, 上面的可以写成:

ByteBuffer [] scatterBuffers = { header, colorMap, imageBody };  
fileChannel.read (scatterBuffers);

  ScatteringByteChannel 是一个具有两个附加读方法的通道:

  • long read( ByteBuffer[] dsts );
  • long read( ByteBuffer[] dsts, int offset, int length );  

  聚集写入 类似于分散读取,只不过是用来写入。它也有接受缓冲区数组的方法:

  • long write( ByteBuffer[] srcs );
  • long write( ByteBuffer[] srcs, int offset, int length );

  聚集写对于把一组单独的缓冲区中组成单个数据流很有用。为了与上面的消息例子保持一致,您可以使用聚集写入来自动将网络消息的各个部分组装为单个数据流,以便跨越网络传输消息。

 字符集

  这是一个在处理大文本文件字符编码转换时碰到的问题,即使用CharsetDecoder.decode()方法解码一个MappedByteBuffer对象时,如果这个MBB对象的长度设置的不好,可能会出现“java.nio.charset.MalformedInputException:Malformed
input length is 2.”的错误。但是如果直接使用Charset.decode()方法,则不会出现这样的错误。两端代码片段如下: 

 File infile = new File(inFilename);
RandomAccessFile raf = new RandomAccessFile(infile, "r");
MappedByteBuffer mbb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY,,);
Charset inCharset = Charset.forName("GBK");
Charset outCharset = Charset.forName("UTF-8"); CharsetDecoder inDecoder = inCharset.newDecoder();
CharsetEncoder outEncoder = outCharset.newEncoder(); CharBuffer cb = inDecoder.decode(mbb); ByteBuffer outbb = outEncoder.encode(cb); CharSequence str = new String(outbb.array());
System.out.println("str is :"+str);

  直接使用Charset.decode()方法:

File infile = new File(inFilename);
RandomAccessFile raf = new RandomAccessFile(infile, "r");
MappedByteBuffer mbb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY,0,6000);
Charset inCharset = Charset.forName("GBK");
Charset outCharset = Charset.forName("UTF-8"); //CharsetDecoder inDecoder = inCharset.newDecoder();
//CharsetEncoder outEncoder = outCharset.newEncoder(); CharBuffer cb = inCharset.decode(mbb); ByteBuffer outbb = outCharset.encode(cb); CharSequence str = new String(outbb.array());
System.out.println("str is :"+str);

 文件锁定

  读文件时将获得一个共享锁,写文件时将获得一个 排它锁。

   要获取文件的一部分上的锁,你要调用一个打开的FileChannel上的lock()方法。注意,如果要获取一个排它锁,你必须以写方式打开文件。

RandomAccessFile raf = new RandomAccessFile( "usefilelocks.txt", "rw" );
FileChannel fc = raf.getChannel();
FileLock lock = fc.lock( start, end, false );

  操作完成后,需要释放锁,最好放在finally中执行:

lock.release();  

 正则表达式

  正则表达式并不是NIO特有的特性,但是使用正则表达式,使用Pattern和Matcher将可以快速地完成一些查找、替换、校验的工作。

  

NIO基础篇(三)的更多相关文章

  1. NIO相关基础篇三

    转载请注明原创出处,谢谢! 说在前面 上篇NIO相关基础篇二,主要介绍了文件锁.以及比较关键的Selector,本篇继续NIO相关话题内容,主要谈谈一些Linux 网络 I/O模型.零拷贝等一些内容, ...

  2. docker+k8s基础篇三

    Docker+K8s基础篇(三) kubernetes上的资源 A:k8s上的常用资源 Pod的配置清单 A:Pod上的清单定义 B:Pod创建资源的方法 C:spec下其它字段的介绍 Pod的生命周 ...

  3. Hybrid APP基础篇(三)->Hybrid APP之Native和H5页面交互原理

    本文已经不维护,新地址: http://www.cnblogs.com/dailc/p/8097598.html 说明 Hybrid模式原生和H5交互原理 目录 前言 参考来源 前置技术要求 楔子 A ...

  4. Python基础篇(三)_函数及代码复用

    Python基础篇_函数及代码复用 函数的定义.使用: 函数的定义:通过保留字def实现. 定义形式:def <函数名>(<参数列表>): <函数体> return ...

  5. JavaScript笔记基础篇(三)

    针对前段JS获取当前时间或者对时间数据处理方法汇总: javascript 字符串转化为日期 Java代码   var s="2010-5-18 12:30:20"; var t= ...

  6. NIO基础篇(二)

    Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件.这样,一个单独的线程可以管理多个channel,从而管理多个网络连接. 传统的 ...

  7. NIO基础篇(一)

    1.NIO与传统IO的比较 Java的NIO(New IO)是不同于旧IO的,旧的IO是基于字节流和字符流的,是阻塞的IO.NIO是基于通道(Channel)和缓冲区(Buffer)的,是非阻塞的IO ...

  8. 前端开发之JavaScript基础篇三

    主要内容: 1.创建对象的几种方式 2.JavaScript内置对象 3.JavaScript错误--Throw.Try 和 Catch 4.JavaScript 表单验证 一.创建对象的几种方式 1 ...

  9. Java面试题-基础篇三(干货)

    这些JAVA基础题确定都会了吗? 31.String s = new String("xyz");创建了几个StringObject?是否可以继承String类? 两个或一个都有可 ...

随机推荐

  1. bzoj usaco 金组水题题解(2)

    续.....TAT这回不到50题编辑器就崩了.. 这里塞40道吧= = bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害 比较经典的最小割?..然而 ...

  2. JS数组中shift()和push(),unshift()和pop()操作方法使用

    Javascript为数组专门提供了push和pop()方法,以便实现类似栈的行为.来看下面的例子: var colors=new Array();       //创建一个数组 var count= ...

  3. 性能测试资源监控工具nmon使用方法

    1.简述  nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具,相对于其它一些系统资源监控工具来说,nmon所记录的信息是比较全面的,它能在系统运行过程中实时地捕捉系统资源的使用 ...

  4. MySql优化子查询

    用子查询语句来影响子查询中产生结果rows的数量和顺序. For example: SELECT * FROM t1 WHERE t1.column1 IN (SELECT column1 FROM ...

  5. CCF系列之有趣的数(201312-4)

    题目链接: http://115.28.138.223:81/view.page?opid=4 试题名称: 有趣的数 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 我们把一个 ...

  6. ASP.NET导出word实例

    ASP.NET导出word实例 最近遇到一个题目就是如何在asp.net中将数据导出到word中,由于数据是动态的,所以需要在后台拼出想要的的格式,翻遍了网页找出了一个比较满意的代码,感谢那位高手.代 ...

  7. C语言 模2除法

    C语言中的模2除法: 模2除做法与算术除法类似,但每一位除(减)的结果不影响其它位,即不向上一位借位.所以实际上就是异或.然后再移位移位做下一位的模2减. 步骤如下: a.用除数对被除数最高n位做模2 ...

  8. (1-1)SpringCloud-Eureka:服务的注册与发现

    SpringCloud Eureka是SpringCloud Netflix服务套件中的一部分,它基于Netflix Eureka做了二次封装,主要负责完成微服务架构中的服务治理功能.下面来做一个示例 ...

  9. RocketMQ环境搭建(双master模式)

    介绍: 多Master模式,一个集群无Slave,全是Master,例如2个Master或者3个Master. 优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时, ...

  10. sed 变量替换和Linux的特殊符号大全

    1 sed支持两种方式的变量替换,建议使用下面的第二种,比较简单 这样就可以给变量a赋值很多特殊字符了,比如 赋值a='!@#¥%……' sed -n 's/echo/'"$a"' ...