`
orange5458
  • 浏览: 347642 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

nio(三) FileChannel

 
阅读更多

1.简介

    JDK1.4在IO的基础上引入NIO,其目的在于提高速度。速度的提高来自于所使用的结构更接近于操作系统执行I/O的方式:通道和缓冲器。唯一直接与通道交互的缓冲器是ByteBuffer。

    FileChannel是用于读取、写入、映射和操作文件的通道,目前不支持直接创建该对象,可通过FileInputStream,FileOutputStream,RandomAccessFile的getChannel方法获取FileChannel对象。

    通过 FileInputStream 实例的 getChannel 方法所获得的通道将允许进行读取操作。通过 FileOutputStream 实例的 getChannel 方法所获得的通道将允许进行写入操作。最后,如果使用模式 "r" 创建 RandomAccessFile 实例,则通过该实例的 getChannel 方法所获得的通道将允许进行读取操作,如果使用模式 "rw" 创建实例,则获得的通道将允许进行读取和写入操作。

    如果从文件输出流中获得了允许进行写入操作的文件通道,并且该输出流是通过调用 FileOutputStream(File,boolean) 构造方法且为第二个参数传入 true 来创建的,则该文件通道可能处于追加模式。在此模式中,每次调用相关的写入操作都会首先将位置移到文件的末尾,然后再写入请求的数据。在单个原子操作中是否移动位置和写入数据是与系统相关的,因此是未指定的。

    文件通道在其文件中有一个当前 position,可对其进行查询和修改。该文件本身包含一个可读写的长度可变的字节序列,并且可以查询该文件的当前#size大小。写入的字节超出文件的当前大小时,则增加文件的大小;截取 该文件时,则减小文件的大小。文件可能还有某个相关联的元数据,如访问权限、内容类型和最后的修改时间;此类未定义访问元数据的方法。
    除了字节通道中常见的读取、写入和关闭操作外,此类还定义了下列特定于文件的操作:

1)以不影响通道当前位置的方式,对文件中绝对位置的字节进行读取或写入。

2)将文件中的某个区域直接映射到内存中;对于较大的文件,这通常比调用普通的 read 或 write 方法更为高效。

3)强制对基础存储设备进行文件的更新,确保在系统崩溃时不丢失数据。

4)以一种可被很多操作系统优化为直接向文件系统缓存发送或从中读取的高速传输方法,将字节从文件传输到某个其他通道中,反之亦然。

5)可以锁定某个文件区域,以阻止其他程序对其进行访问。

    多个并发线程可安全地使用文件通道。可随时调用关闭方法,正如 Channel 接口中所指定的。对于涉及通道位置或者可以更改其文件大小的操作,在任意给定时间只能进行一个这样的操作;如果尝试在第一个操作仍在进行时发起第二个操作,则会导致在第一个操作完成之前阻塞第二个操作。可以并发处理其他操作,特别是那些采用显式位置的操作;但是否并发处理则取决于基础实现,因此是未指定的。
    确保此类的实例所提供的文件视图与同一程序中其他实例所提供的相同文件视图是一致的。但是,此类的实例所提供的视图不一定与其他并发运行的程序所看到的视图一致,这取决于基础操作系统所执行的缓冲策略和各种网络文件系统协议所引入的延迟。不管其他程序是以何种语言编写的,而且也不管是运行在相同机器还是不同机器上都是如此。此种不一致的确切性质取决于系统,因此是未指定的。

    文件通道的状态与其 getChannel 返回该通道的对象密切相关。显式或者通过读取或写入字节来更改通道的位置将更改发起对象的文件位置,反之亦然。通过文件通道更改此文件的长度将更改通过发起对象看到的长度,反之亦然。通过写入字节更改此文件的内容将更改发起对象所看到的内容,反之亦然。

    由于通道只能与ByteBuffer交互,所以必然存在字符和字节之间的转化问题,转化方法有两个:

1)使用Charset进行encode和decode实现字符和字节

2)使用Channels类将Channel转化为Reader或者Writer

     最后要说的是旧的IO包已经使用NIO重新实现过,以便充分利用这种速度提高,因此,即使我们不显式地用NIO编写代码,也能从中受益。

2.实例

package com.siyuan.test.jdk.nio;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

public class FileChannelTest {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		
		int BUFFER_SIZE = 1024;
		Charset gbk = Charset.forName("GBK");
		/*
		 * 使用FileChannel写文件
		 */
		FileChannel fcW = new FileOutputStream("D:/test/fileChannelTest.txt").getChannel();
		System.out.println(getFileChannelStatus(fcW));
		fcW.write(gbk.encode("我是中国人")); //通过Charset.encode()方法创建的ByteBuffer已经进行了flip操作
		System.out.println(getFileChannelStatus(fcW));
		fcW.close();
		
		/*
		 * 使用FileChannel读文件
		 */
		//FileChannel fcR = fcW; //java.nio.channels.NonReadableChannelException
		FileChannel fcR = new FileInputStream("D:/test/fileChannelTest.txt").getChannel();
		System.out.println(getFileChannelStatus(fcR));
		ByteBuffer bBuffer = ByteBuffer.allocate(BUFFER_SIZE);
		while (fcR.read(bBuffer) != -1) {
			bBuffer.flip(); //
			System.out.println(Charset.forName("GBK").decode(bBuffer));
			bBuffer.clear(); //
		}
		System.out.println(getFileChannelStatus(fcR));
		fcR.close();
		
		/*
		 * 使用Channels创建Reader读取文件
		 */
		FileChannel fcR2 = new FileInputStream("D:/test/fileChannelTest.txt").getChannel();
		BufferedReader bufR = new BufferedReader(Channels.newReader(fcR2, "GBK"));
		String bufStr = null;
		while ((bufStr = bufR.readLine()) != null) {
			System.out.println(bufStr);
		}
		bufR.close();
		
		/*
		 * 从一个文件读取内容到另一个文件
		 * 比较不同的方式下的速度
		 */
		// method 1
		long timeStart0 = System.currentTimeMillis();
		InputStream in = new BufferedInputStream(new FileInputStream("D:/test/2013-05-28.zip"));
		OutputStream out = new BufferedOutputStream(new FileOutputStream("D:/test/2013-05-28-bak0.zip"));
		byte[] buf = new byte[BUFFER_SIZE];
		int length = 0;
		while ((length = in.read(buf, 0, buf.length)) != -1) {
			out.write(buf, 0, length);
		}
		in.close();
		out.close();
		System.out.println("Time cost of method 0 : " + (System.currentTimeMillis() - timeStart0));
		
		// method 1
		long timeStart1 = System.currentTimeMillis();
		FileChannel fcIn = new FileInputStream("D:/test/2013-05-28.zip").getChannel();
		FileChannel fcOut = new FileOutputStream("D:/test/2013-05-28-bak1.zip").getChannel();
		while (fcIn.read(bBuffer) != -1) {
			bBuffer.flip();
			fcOut.write(bBuffer);
			bBuffer.clear();
		}
		fcIn.close();
		fcOut.close();
		System.out.println("Time cost of method 1 : " + (System.currentTimeMillis() - timeStart1));
		
		// method 2
		long timeStart2 = System.currentTimeMillis();
		FileChannel fcIn2 = new FileInputStream("D:/test/2013-05-28.zip").getChannel();
		FileChannel fcOut2 = new FileOutputStream("D:/test/2013-05-28-bak2.zip").getChannel();
		fcIn2.transferTo(0, fcIn2.size(), fcOut2);
		fcIn2.close();
		fcOut2.close();
		System.out.println("Time cost of method 2 : " + (System.currentTimeMillis() - timeStart2));
		
		// method 3
		long timeStart3 = System.currentTimeMillis();
		FileChannel fcIn3 = new FileInputStream("D:/test/2013-05-28.zip").getChannel();
		FileChannel fcOut3 = new FileOutputStream("D:/test/2013-05-28-bak3.zip").getChannel();
		fcOut3.write(fcIn3.map(FileChannel.MapMode.READ_ONLY, 0, fcIn3.size()));
		fcIn3.close();
		fcOut3.close();
		System.out.println("Time cost of method 3 : " + (System.currentTimeMillis() - timeStart3));
	}
	
	public static String getFileChannelStatus(FileChannel fc) throws IOException {
		StringBuilder fcStatus = new StringBuilder();
		fcStatus.append("位置:").append(fc.position())
			.append(",大小:").append(fc.size());
		return fcStatus.toString();
	}
	
}

    运行结果

位置:0,大小:0
位置:10,大小:10
位置:0,大小:10
我是中国人
位置:10,大小:10
我是中国人
Time cost of method 0 : 245
Time cost of method 1 : 875
Time cost of method 2 : 581
Time cost of method 3 : 905

 3.参考资料

JDK

THINKING IN JAVA

分享到:
评论

相关推荐

    muyinchen#woker#07 Java的NIO之FileChannel1

    7.1 打开一个FileChannel 7.2 从FileChannel通道中读取数据 7.3 向FileChannel中写入数据: 7.4 关闭FileCha

    JavaNIO chm帮助文档

    Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道之间的数据传输 Java NIO系列教程(六) Selector Java NIO系列教程(七) FileChannel Java NIO系列教程(八) ...

    java网络编程NIO视频教程

    01-Java NIO-课程简介.mp4 02-Java NIO-概述.mp4 03-Java NIO-Channel-概述.mp4 04-Java NIO-Channel-FileChannel(介绍和示例).mp4 ...14-Java NIO-Buffer-三个属性和类型.mp4 15-Java NIO-Buffer-分配和读写数据.mp4

    Java NIO实战开发多人聊天室

    14-Java NIO-Buffer-三个属性和类型.mp4 17-Java NIO-Buffer-缓冲区分片.mp4 18-Java NIO-Buffer-只读缓冲区.mp4 19-Java NIO-Buffer-直接缓冲区.mp4 21-Java NIO-Selector-概述.mp4 23-Java NIO-Selector-示例代码...

    NIO(byteBuffer)按行读取文件

    使用nio byteBuffer 实现按行读取文件(大文件) 在window/linux/macOS上均测试通过 对于中文乱码也已处理成功 完整注释,可随需求更改 有问题请邮件:mly610865580@126.com

    jruby-stdin-channel:JRuby 扩展为 STDIN 公开可中断的 NIO FileChannel

    jruby-stdin-channel JRuby Java 扩展 gem,它从 Java System.in stdin 中提取可中断的FileChannel。 使用这个 gem,在阻塞read方法上调用close将解除阻塞,这与普通的 JRuby $stdin 。 使用close转义阻塞读取仅适用...

    2021最新-Java NIO视频教程-视频教程网盘链接提取码下载 .txt

    教程内容涵盖:阻塞和非阻塞IO、Channel通道、Buffer缓冲区、Selector选择器、Pipe管道、FileLock文件锁,以及Path、Files、异步FileChannel和Charset字符编码等,并通过一个多人聊天室的综合案例,把所有的NIO知识...

    01_尚硅谷_Java NIO_课件_V1.01

    1.1 阻塞 IO 2.3 FileChannel 介绍和示例 2.4 FileChannel 操作详解

    mina:Java Nio Apache Mina Java Nio

    java-nio java-nio ...AbstractInterruptibleChannel, AbstractSelectableChannel, DatagramChannel, FileChannel, Pipe.SinkChannel, Pipe.SourceChannel, SelectableChannel, ServerSocketChannel, Socke

    muyinchen#woker#06 Java的NIO之不同channel之间传输数据1

    两个通道之间传输数据的方式有两种,分别是:FileChannel 的transferFrom()方法可以将数据从源通道传输到FileChannel中(这个方法在

    编写一个java应用程序将一个包含多个子目录和文件的目录复制到另外一个指定的目录下

    import java.nio.channels.FileChannel; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import javax.swing.filechooser.FileFilter; 实验...

    JDK_seaswalker.tar.gz

    FileChannel Buffer URLConnection NIO Process HashMap LinkedHashMap TreeMap ConcurrentHashMap ConcurrentLinkedQueue ThreadPool ThreadLocal Reflection ScheduledThreadPool ...

    java二叉树源码-scodec-bits:提供用于处理位和字节的不可变数据类型

    源(如java.nio.channels.ReadableByteChannel和java.nio.channels.FileChannel一起使用的方法,它们允许对来自各种源的位和字节进行高效、惰性的访问和操作。 十六进制和二进制字符串字面量是通过所支持的hex和bin...

    sambox:一个PDFBox分支,打算用作Sejda和PDFsam的PDF处理程序

    SAMBox使用允许使用基于java.nio.channels.FileChannel , java.io.InputStream和java.nio.MappedByteBuffer的提供的实现之一(是否缓冲)。 通过使用java.lang.StringBuilder池最小化GC。 通过绑定视图的概念直接...

    java8源码-netty-learn:这是一个用于netty学习的工程

    ##NIO基础 三大组件 Channel & Buffer channel有点类似于stream,它就是读写数据的双向通道,可以从channel将数据读入buffer,也可以将buffer中的数据写入到channel 中,而stream只能完成一种 常见的Channel有 ...

    ip地址库 很全的库

    import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /* * ...

    tomcat-7_API_帮助文档

    There are some Linux bugs reported against the NIO sendfile behavior, make sure you have a JDK that is up to date, or disable sendfile behavior in the Connector. 6427312: (fc) FileChannel....

    txt文档阅读器

    import java.nio.channels.FileChannel; import java.text.DecimalFormat; import java.util.Vector; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import ...

    java pdf 查看器

    import java.nio.channels.FileChannel; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Box; import ...

Global site tag (gtag.js) - Google Analytics