jdK1.4的java.nio.*包中引入了JavaI/O类库,其目的在于提高速度。实际上,旧的I/O包已经使用nio重新实现过,以便充分利用这种速度提高,因此,即使我们不显示的用nio编写代码,也能从中受益。
速度的提高来自于所使用的结构更加接近操作系统执行I/O的方式:通道和缓冲器。我们可以把它想象成一个煤矿,通道是一个包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。卡车载满煤炭而归,我们再从卡车上获得煤炭。也就是说,我们并没有直接和通道打交道,我们只是和缓冲器交互,并把缓冲器派送到通道。通道要么从缓冲器获得数据,要么向缓冲器发送数据。
唯一直接与通道交互的缓冲器是ByteBuffer---也就是说,可以存储未加工字节的缓冲器。当我们查询JDK文档中的java.nio.ByteBuffer时,会发现它是相当基础的类:通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法选择集,用于以原始的字节形式或基本数据类型输出和读取数据。但是,没有办法输出或读取对象,即使是字符串对象也不行。这种处理虽然很低级,但却正好,因为这是大多数操作系统中更有效的映射方式。
旧的IO类库有三个类被修改,用以产生FileChannel(用于读取、写入、映射和操作文件的通道)。这三个被修改的类是FileInputStream、FileOutputStream以为用于既读又写的RandomAccessFile。注意这些是字节操纵流,与低层的nio性质一致。Reader和Writer这种字符模式类不能用于产生通道;但是java.nio.channels.Channels类提供类实用方法,用以在通道中产生Reader和Writer。
下面的简单实例演示了上面三种类型的流,用以产生可以写的、可读可写的及可读的通道。
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()来告知FileChannel向ByteBuffer存储字节,就必须调用缓冲器上的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 NIO,适合初学者学习JAVA语言及项目开发模式
1、对于Java基础技术体系(包括JVM、类装载机制、多线程并发、IO、网络)有一定的掌握和应用经验。 掌握JVM内存分配、JVM垃圾回收;类装载机制; 性能优化; 反射机制;多线程;IO/NIO; 网络编程;常用数据结构和...
39_NIO中Scattering与Gathering深度解析 40_Selector源码深入分析 41_NIO网络访问模式分析 42_NIO网络编程实例剖析 43_NIO网络编程深度解析 44_NIO网络客户端编写详解 45_深入探索Java字符集编解码 46_字符集编解码...
java8 集合源码分析 JavaBooks 推荐书单 书单 01.JVM 深入理解Java虚拟机 02.NIO Netty实战 Netty权威指南 ...Java编程思想(Thinking in Java)、Java核心技术(Core Java) ,Java8 实战(Java in action),Eff
Java编程方法论-响应式篇-RxJava 分享视频 已完结 bilibili: 油管: Java编程方法论-响应式篇-Reactor 分享视频 已完结 B站: 油管: Java编程方法论-响应式篇-Reactor-Netty 分享视频 在分享 相关博文: 视频分享:...
35_Java NIO核心类源码解读与分析 36_文件通道用法详解 37_Buffer深入详解 38_NIO堆外内存与零拷贝深入讲解 39_NIO中Scattering与Gathering深度解析 40_Selector源码深入分析 41_NIO网络访问模式分析 42_NIO网络编程...
欢迎使用Java编程语言 概述 中国,东北林业大学,软件工程,java编程语言,2021年 Java程序设计。此课程为东北林业大学软件工程专业第4学期的一门专业选修课,课程包含32理论学时16实验学时主讲教师:王波老师 课程...
第35讲:Java NIO核心类源码解读与分析 第36讲:文件通道用法详解 第37讲:Buffer深入详解 第38讲:NIO堆外内存与零拷贝深入讲解 第39讲:NIO中Scattering与Gathering深度解析 第40讲:Selector源码深入分析 ...
磁盘操作、字节操作、字符操作、对象操作、网络操作、NIO Java 虚拟机 运行时数据区域、垃圾收集、内存分配机制、类加载机制、性能调优监控工具 Java 设计模式 Java 常见的 10 余种设计模式,全 23 种设计模式...
面向对象思想 集合框架 IO流 多线程与并发 异常处理 网络编程 数据库 MySQL Oracle JDBC C3P0 Druid 前端技术 HTML CSS JavaScript jQuery Ajax Vue webpack elementUI 微信小程序 动态网页 Servlet Jsp EL JSTL ...
HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件、客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++、C#、Delphi、E(易语言)、Java、Python 等编程语言接口...