`

java NIO (Java编程思想)

 
阅读更多

    jdK1.4的java.nio.*包中引入了JavaI/O类库,其目的在于提高速度。实际上,旧的I/O包已经使用nio重新实现过,以便充分利用这种速度提高,因此,即使我们不显示的用nio编写代码,也能从中受益。

    速度的提高来自于所使用的结构更加接近操作系统执行I/O的方式:通道和缓冲器。我们可以把它想象成一个煤矿,通道是一个包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。卡车载满煤炭而归,我们再从卡车上获得煤炭。也就是说,我们并没有直接和通道打交道,我们只是和缓冲器交互,并把缓冲器派送到通道。通道要么从缓冲器获得数据,要么向缓冲器发送数据。

    唯一直接与通道交互的缓冲器是ByteBuffer---也就是说,可以存储未加工字节的缓冲器。当我们查询JDK文档中的java.nio.ByteBuffer时,会发现它是相当基础的类:通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集,用于以原始的字节形式或基本数据类型输出和读取数据。但是,没有办法输出或读取对象,即使是字符串对象也不行。这种处理虽然很低级,但却正好,因为这是大多数操作系统中更有效的映射方式。

    旧的IO类库有三个类被修改,用以产生FileChannel(用于读取、写入、映射和操作文件的通道)。这三个被修改的类是FileInputStreamFileOutputStream以为用于既读又写的RandomAccessFile。注意这些是字节操纵流,与低层的nio性质一致。ReaderWriter这种字符模式类不能用于产生通道;但是java.nio.channels.Channels类提供类实用方法,用以在通道中产生ReaderWriter

    下面的简单实例演示了上面三种类型的流,用以产生可以写的、可读可写的及可读的通道。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class GetChannel {
 private static final int BSIZE = 1024;
 public static void main(String[] args) throws IOException{
  //write a file
  FileChannel fc = new FileOutputStream("data.txt").getChannel();
  fc.write(ByteBuffer.wrap("hello world".getBytes()));
  fc.close();
  //加到文件末尾
  fc = new RandomAccessFile("data.txt", "rw").getChannel();
  fc.position(fc.size()); //移到文件末尾用position方法
  fc.write(ByteBuffer.wrap(" hello world again".getBytes()));
  fc.close();
  //读取文件
  fc = new FileInputStream("data.txt").getChannel();
  ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
  fc.read(buffer); //通道从缓冲器中读取内容
  buffer.flip(); //读了之后要flip一下
  while(buffer.hasRemaining())
   System.out.print((char)buffer.get());
 }
}

    对于这里展示的任何流类,getChannel()将会产生一个FileChannel。通道是一种相当基础的东西,可以向它传送关于读写的ByteBuffer。

    将字节存放于ByteBuffer的方法之一是:使用“put”方法直接填充,填入一个或者多个字节,或基本数据类型的值。也可以使用wrap()方法将已经存在的字节数组“包装”到ByteBuffer中。

    对于只读访问,我们必须显式的使用静态allocate()方法来分配ByteBuffer。nio的目标就是快读移动大量数据,因此ByteBuffer的大小就显得尤为重要。甚至达到更高的速度也有可能,方法就是allocateDirect而不是allocate,以产生一个与操作系统更高耦合性的直接缓冲器。但是,这种分配开支会更大,并且具体实现也随着操作系统的不同而不同。

    一旦调用read()来告知FileChannelByteBuffer存储字节,就必须调用缓冲器上的flip(),让它做好让别人读取字节的准备。如果我们打算使用缓冲器执行进一步的read()操作,我们必须得调用clear()来为每个read()做好准备。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class ChannelCopy {
 private static final int BSIZE = 1024;
 public static void main(String[] args) throws IOException{
  if(args.length != 2){
   System.out.println("arguments: sourceFile destFile");
   System.exit(1);
  }
  FileChannel
   in = new FileInputStream(args[0]).getChannel(),
   out = new FileOutputStream(args[1]).getChannel();
  ByteBuffer buffer = ByteBuffer.allocate(BSIZE);
  while(in.read(buffer) != -1){
   buffer.flip(); //prepare for writing
   out.write(buffer);
   buffer.clear(); //prepare for reading
  }
 }
}

    每次read()操作之后,就会将数据输入到缓冲器中,flip()则是准备缓冲器以便她的信息可以由write()提取。write()操作之后,信息扔存在缓冲器中,接着clear()操作则对所有的内部指针重新安排,以便缓冲器在另一个read()操作期间能够做好接受数据的准备。

    然而,上面那个程序并不是处理此类操作的理想方式。特殊方法transferTo()和transferFrom()则允许我们将一个通道和另一个通道直接相连。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;

public class TransferTo {
 public static void main(String[] args) throws IOException{
  if(args.length != 2){
   System.out.println("arguments: sourceFile destFile");
   System.exit(1);
  }
  FileChannel
   in = new FileInputStream(args[0]).getChannel(),
   out = new FileOutputStream(args[1]).getChannel();
  in.transferTo(0, in.size(), out);
  //或者
  out.transferFrom(in, 0, in.size());
 }
}

 

分享到:
评论

相关推荐

    JAVA学习笔记

    JAVA学习笔记,包含JAVA编程思想,JAVA多线程设计模式,JAVA网络编程,以及JAVA NIO,适合初学者学习JAVA语言及项目开发模式

    JAVA中级书籍

    1、对于Java基础技术体系(包括JVM、类装载机制、多线程并发、IO、网络)有一定的掌握和应用经验。 掌握JVM内存分配、JVM垃圾回收;类装载机制; 性能优化; 反射机制;多线程;IO/NIO; 网络编程;常用数据结构和...

    精通并发与 netty 视频教程(2018)视频教程

    39_NIO中Scattering与Gathering深度解析 40_Selector源码深入分析 41_NIO网络访问模式分析 42_NIO网络编程实例剖析 43_NIO网络编程深度解析 44_NIO网络客户端编写详解 45_深入探索Java字符集编解码 46_字符集编解码...

    java8集合源码分析-JavaBooks:书籍

    java8 集合源码分析 JavaBooks 推荐书单 书单 01.JVM 深入理解Java虚拟机 02.NIO Netty实战 Netty权威指南 ...Java编程思想(Thinking in Java)、Java核心技术(Core Java) ,Java8 实战(Java in action),Eff

    java版直播间源码-woker:唤醒者

    Java编程方法论-响应式篇-RxJava 分享视频 已完结 bilibili: 油管: Java编程方法论-响应式篇-Reactor 分享视频 已完结 B站: 油管: Java编程方法论-响应式篇-Reactor-Netty 分享视频 在分享 相关博文: 视频分享:...

    精通并发与netty视频教程(2018)视频教程

    35_Java NIO核心类源码解读与分析 36_文件通道用法详解 37_Buffer深入详解 38_NIO堆外内存与零拷贝深入讲解 39_NIO中Scattering与Gathering深度解析 40_Selector源码深入分析 41_NIO网络访问模式分析 42_NIO网络编程...

    java-course

    欢迎使用Java编程语言 概述 中国,东北林业大学,软件工程,java编程语言,2021年 Java程序设计。此课程为东北林业大学软件工程专业第4学期的一门专业选修课,课程包含32理论学时16实验学时主讲教师:王波老师 课程...

    精通并发与netty 无加密视频

    第35讲:Java NIO核心类源码解读与分析 第36讲:文件通道用法详解 第37讲:Buffer深入详解 第38讲:NIO堆外内存与零拷贝深入讲解 第39讲:NIO中Scattering与Gathering深度解析 第40讲:Selector源码深入分析 ...

    飞秋java源码-interviewNote:面试笔记

     磁盘操作、字节操作、字符操作、对象操作、网络操作、NIO Java 虚拟机  运行时数据区域、垃圾收集、内存分配机制、类加载机制、性能调优监控工具 Java 设计模式  Java 常见的 10 余种设计模式,全 23 种设计模式...

    百度地图毕业设计源码-Java-Notes:2020Java快速成长学习路线,从0到1的过程,打破你知识的盲区,渐渐爱上Java,我想对还是小

    面向对象思想 集合框架 IO流 多线程与并发 异常处理 网络编程 数据库 MySQL Oracle JDBC C3P0 Druid 前端技术 HTML CSS JavaScript jQuery Ajax Vue webpack elementUI 微信小程序 动态网页 Servlet Jsp EL JSTL ...

    HP-Socket下载

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件、客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++、C#、Delphi、E(易语言)、Java、Python 等编程语言接口...

Global site tag (gtag.js) - Google Analytics