Java NIO

输入/输出流都是阻塞式的(eg:InputStream的read方法从流中读取数据时,如果数据源中没有数据,它会阻塞该线程)

传统的输入流、输出流都是通过字节的移动来处理,面向流的输入/输出系统只能一次处理一个字节,因此效率不高。

Java新IO将文件或文件的一段区域映射到内存中,效率比较高。

Channel(通道)和Buffer(缓冲)是新IO中的两个核心对象在新IO系统中所有的数据都需要通过通道传输:Channel和传统的InputStream、OutputStream最大的区别在于它提供了一个map()方法,通过该map()方法可以直接将“一块数据”映射到内存中。

新IO还提供了用于将Unicode字符串映射成字符序列以及逆映射操作的Charset类,也提供了用于支持非阻塞式输入/输出的Selector类。


Buffer中有三个重要概念:

容量(capacity):最大数据量;

界限(limit):limit后的数据既不可以被读,也不可以被写。

位置(position):下一个可以被读取或者写入缓冲区位置的索引,第一个位置的索引是0。

import java.nio.CharBuffer;

public class BufferTest {
	public static void main(String[] args) {
		CharBuffer charBuffer = CharBuffer.allocate(6);
		System.out.println("容量="+charBuffer.capacity());
		System.out.println("界限limit="+charBuffer.limit());
		System.out.println("位置="+charBuffer.position());
		charBuffer.put('1');
		charBuffer.put('1');
		charBuffer.put('2');
		System.out.println("加入三个元素后的位置索引="+charBuffer.position());
		
		charBuffer.flip();
		System.out.println("调用flip()方法后,limit="+charBuffer.limit());
		System.out.println("调用flip()方法后,位置索引="+charBuffer.position());
		//开始取数据
		System.out.println("取出第一个元素="+charBuffer.get(0));
		System.out.println("取出第一个元素后,位置索引="+charBuffer.position());
		
		//调用clear()
		charBuffer.clear();
		System.out.println("调用clear()方法后,limit="+charBuffer.limit());
		System.out.println("调用clear()方法后,位置索引="+charBuffer.position());
		System.out.println("取出第三个元素="+charBuffer.get(2));
		
		charBuffer.put('1');
		charBuffer.put('2');
		charBuffer.put('3');
		charBuffer.put('4');
		charBuffer.put('5');
		charBuffer.put('6');
		
		System.out.println("重新put值之后,取出第三个元素="+charBuffer.get(2));
		System.out.println("取出第三个元素后,位置索引="+charBuffer.position());
	}
}


调用Buffer的flip()后,该方法将limit设置为position所在位置,并将position设置为0,即Buffer的读写指针又回到了开始位置,调用flip()方法之后,Buffer为输出数据做好准备;当Buffer输出数据结束后,Buffer调用clear()方法,clear()方法不是清空数据,它只是将position的设置为0,将limit设置成capacity,这样再次向Buffer中装入数据做好准备,put数据的时候将会覆盖之前的数据。

实际使用较多的是ByteBuffer和CharBuffer,ByteBuffer类还有一个子类:MappedByteBuffer,它用于表示Channel将磁盘文件部分或全部内容映射到内存中后得到的结果,通常MappedByteBuffer对象由Channel的map()方法返回。


Channel(通道)

(1)Channel可以直接将指定文件的部分或全部直接映射成Buffer。

(2)程序不能直接访问Channel中的数据,读写都不允许,Channel只能与Buffer进行交互。新IO中的Channel是按功能划分的,eg:Pipe.SinkChannel、Pipe.SourceChannel是用于支持线程之间通信的管道Channel;ServerSocketChannel、SocketChannel是用于支持TCP网络通信的Channel;而DatagramChannel则是用于支持UDP网络通信的Channel。

Channel最常用的三个方法是:map()、read()、write(),其中map()方法用于将Channel对应的部分或全部数据映射成ByteBuffer;而read()或write()方法都有一系列重载形式。

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

public class FileChannelTest {

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		File file = new File("InputStreamTest.java");
		try {
			FileChannel inFileChannel = new FileInputStream(file).getChannel();
			FileChannel outFileChannel = new FileOutputStream("file.txt").getChannel();
			
			//将inFileChannel里的全部数据映射到ByteBuffer中
			MappedByteBuffer mappedByteBuffer = inFileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
			//直接将buff中数据全部读出
			outFileChannel.write(mappedByteBuffer);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

读取任意字节数据,防止使用map()方法一次将所有的文件内容映射到内存引起性能下降

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;

public class ReadFile {

	public static void main(String[] args) {
			try(FileChannel fileChannel = new FileInputStream("InputStreamTest.java").getChannel();) {
				//一次去1024字节
				ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
				while(fileChannel.read(byteBuffer)!=-1){
					//锁定byteBuffer中的空白区,开始读取数据
					byteBuffer.flip();
					//创建CharsetDecoder对象
					Charset charset = Charset.forName("GBK");
					//将ByteBuffer中的内容转码
					CharBuffer charBuffer = charset.decode(byteBuffer);
					System.out.println(charBuffer);
					//为下次装入数据做准备
					byteBuffer.clear();
					
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值