java语言中文件读取对NIO的具体实现

一:概述
java中对文件的读写原始的实现是使用的BIO模式即读写流,java1.4后引入NIO,读取文件使用的是NIO的同步阻塞模式进行文件的读取,使用通道(channel)去读取一个文件资源,使用缓冲区去存放读写的数据,只不过 Channel本身不能直接访问数据,Channel 只能与Buffer 进行交互。
二:具体实现
(1)通道(channel)
通道是文件读取的核心,通道类似于文件读取的流,每一个通道来确定一个文件的资源并且通 道是双向的,即可以读数据也可以写数据,通道的获取方式有多种方式,每种方式获取的通道具有自己不同的特性。
java给我们提供的关于文件的通道主要实现类有FileChannel类。通道的获取主要有主要以下几种方式:
**方式一:**通过文件的输入和输出流来获取通道,但该种方式获取的通道只能读或者取,如果读的流获取的通道只能去读数据,写数据的话会报权限不足的异常,代码如下:

FileInputStream input = new FileInputStream(new File("D:\\from.txt"));
		FileChannel readChannel = input.getChannel();
FileOutputStream out = new FileOutputStream(new File("D:\\to.txt"));
		FileChannel writeChannel = out.getChannel();

**方式二:**通过RandomAccessFile来获取通道, 通过这种方式获取的通道既可以读又可以写,而且构造函数中还可以进行模式的匹配进行读写模式的切换,代码如下:

RandomAccessFile fromR = new RandomAccessFile(new File("D:\\from.txt"), "rw");
		FileChannel fromChannel = from.getChannel();

其他方式:获取通道的其他方式是使用 Files 类的静态方法 newByteChannel() 获取字节通道。或者通过通道的静态方法 open() 打开并返回指定通道,或者通过Channels工具类来获取通道,代码如下:

FileInputStream in1 = new FileInputStream(from);
		Channel channel = Channels.newChannel(in1);

(2) 缓冲区(Buffer)
缓冲区是用于存放通道读取的数据和通道将要读入的数据。
缓冲区有几个重要的概念如下:
容量(capacity) :表示 Buffer 最大数据容量,缓冲区容量不能为负,并且创建后不能更改。
限制 (limit) :第一个不应该读取或写入的数据的索引,即位于 limit 后的数据不可读写。缓冲区 的限制 不能为负,并且不能大于其容量。
位置 (position):下一个要读取或写入的数据的索引。缓冲区的位置不能为负,并且不能大于其限 制。
标记 (mark) 与重置 (reset) :标记是一个索引,通过 Buffer 中的 mark() 方法指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这个 position.
java中关于缓冲区有以下几个主要的实现类,并且这些类中都有各自的静态方法来获取缓冲区。
主要实现类:
ByteBuffer ,(常用的,分直接缓冲区和非直接缓冲区,前者用allocate()方法获取后者用 allocateDirect()方法来获取)
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
主要的方法:
Buffer 所有子类提供了两个用于数据操作的方法:get()与 put() 方法
get() :读取单个字节
get(byte[] dst):批量读取多个字节到 dst 中
get(int index):读取指定索引位置的字节(不会移动 position)
放到 入数据到 Buffer 中
put(byte b):将给定单个字节写入缓冲区的当前位置
put(byte[] src):将 src 中的字节写入缓冲区的当前位置
put(int index, byte b):将指定字节写入缓冲区的索引位置(不会移动position)
三:文件读写实操
(1)读
使用通道对文件数据进行读取,代码如下:

public static void main(String[] args) throws IOException {
		File from = new File("D:\\from.txt");
		File to = new File("D:\\to.txt");
		FileInputStream in = new FileInputStream(from);
		FileOutputStream out = new FileOutputStream(to);
		 nioRead(in);
		//nioWrite(out);
		//nioReadFensan(in);
		//nioWriteJuce(out); 
		//RandomAccessFile fromR = new RandomAccessFile(from, "rw");
		//RandomAccessFile toR = new RandomAccessFile(to, "rw");
		//transFrom(fromR,toR);
		//transTo(fromR,toR);	
	}
	/**
	 * 读
	 * 
	 * @param input
	 * @throws IOException
	 */
	public static void nioRead(FileInputStream input) throws IOException {
		FileChannel readChannel = input.getChannel();
		// 直接字节缓冲区
		// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
		// 非直接字节缓冲区
		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
		int capacity = byteBuffer.capacity();
		System.out.println("字节缓冲区的容量:" + capacity);
		Boolean direct = byteBuffer.isDirect();
		System.out.println("是否直接缓冲区:" + direct);
		int position = byteBuffer.position();
		System.out.println("缓存区中指针的位置:" + position);
		int limit = byteBuffer.limit();
		System.out.println("缓存区的操作上限:" + limit);
		 byteBuffer.position(10);
		int nextposition = byteBuffer.position();
		System.out.println("缓存区中指定指针的位置:" + nextposition);
		// 开始读取,a为返回的字节数,如果缓冲区中没有容量则返回0,如果要读的文件中没有数据返回为-1
		int msg = readChannel.read(byteBuffer);

		System.out.println("读取的字节数:" + msg);
		System.out.println("读取的数据:" + new String(byteBuffer.array()).trim());

	}
	控制台输出:
	字节缓冲区的容量:1024
    是否直接缓冲区:false
    缓存区中指针的位置:0
    缓存区的操作上限:1024
    缓存区中指定指针的位置:10
    读取的字节数:11
    读取的数据:fromfilemsg
 (2)写
        向文件中写入数据,代码如下:
public static void main(String[] args) throws IOException {
		File from = new File("D:\\from.txt");
		File to = new File("D:\\to.txt");
		FileInputStream in = new FileInputStream(from);
		FileOutputStream out = new FileOutputStream(to);
		 //nioRead(in);
		nioWrite(out);
		//nioReadFensan(in);
		//nioWriteJuce(out); 
		//RandomAccessFile fromR = new RandomAccessFile(from, "rw");
		//RandomAccessFile toR = new RandomAccessFile(to, "rw");
		//transFrom(fromR,toR);
		//transTo(fromR,toR);	
	}
	

	/**
	 * 写
	 * 
	 * @param out
	 * @throws IOException
	 */
	public static void nioWrite(FileOutputStream out) throws IOException {
		FileChannel writeChannel = out.getChannel();
		// 直接字节缓冲区
		// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
		// 非直接字节缓冲区
		String str = new String("123");

		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
		byteBuffer.put(str.getBytes());
		// 向缓冲区中放入数据时position会改变,因此用flip方法将缓冲区位置值0
		byteBuffer.flip();
		int msg = writeChannel.write(byteBuffer);

		System.out.println("写入的字节数" + msg);

	}
	控制台输出:
	写入的字节数3
 (3)分散读取
        分散读取是将从通道中读入的数据放入一个缓冲区数组中,代码如下:
public static void main(String[] args) throws IOException {
		File from = new File("D:\\from.txt");
		File to = new File("D:\\to.txt");
		FileInputStream in = new FileInputStream(from);
		FileOutputStream out = new FileOutputStream(to);
		 //nioRead(in);
		//nioWrite(out);
		nioReadFensan(in);
		//nioWriteJuce(out); 
		//RandomAccessFile fromR = new RandomAccessFile(from, "rw");
		//RandomAccessFile toR = new RandomAccessFile(to, "rw");
		//transFrom(fromR,toR);
		//transTo(fromR,toR);	
	}
	/**
	 * 分散和聚簇,将数据读到多个缓冲区中,从多个缓冲区中写数据
	 * 
	 * @param input
	 * @throws IOException 
	 */
	public static void nioReadFensan(FileInputStream input) throws IOException {
		FileChannel readChannel = input.getChannel();
		// 直接字节缓冲区
		// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
		// 非直接字节缓冲区
		ByteBuffer byteBuffer1 = ByteBuffer.allocate(7);
		ByteBuffer byteBuffer2 = ByteBuffer.allocate(7);
		ByteBuffer[] arr = { byteBuffer1, byteBuffer2 };

		// 开始读取,a为返回的字节数,如果缓冲区中没有容量则返回0,
		Long msg = readChannel.read(arr);
        
		System.out.println("缓冲区1中读取到的数据:" +new String( byteBuffer1.array()));
		System.out.println("缓冲区2中读取到的数据:" +new String( byteBuffer2.array()).trim());
		System.out.println("读取的字节数a:" + msg);

	}
	控制台输出:
	缓冲区1中读取到的数据:fromfil
    缓冲区2中读取到的数据:emsg
    读取的字节数a:11
 (4)聚集写入
      聚集写入是将缓冲区数组中的数据写到文件中,代码如下:
public static void main(String[] args) throws IOException {
		File from = new File("D:\\from.txt");
		File to = new File("D:\\to.txt");
		FileInputStream in = new FileInputStream(from);
		FileOutputStream out = new FileOutputStream(to);
		 //nioRead(in);
		//nioWrite(out);
		//nioReadFensan(in);
		nioWriteJuce(out); 
		//RandomAccessFile fromR = new RandomAccessFile(from, "rw");
		//RandomAccessFile toR = new RandomAccessFile(to, "rw");
		//transFrom(fromR,toR);
		//transTo(fromR,toR);	
	}
	/**
	 * 
	 * 聚集写入
	 * @param out
	 * @throws IOException
	 */
	public static void nioWriteJuce(FileOutputStream out) throws IOException {

		FileChannel writeChannel = out.getChannel();
		// 直接字节缓冲区
		// ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
		// 非直接字节缓冲区
		String str = new String("123");
		String str2 = new String("456");
		ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
		ByteBuffer byteBuffer2 = ByteBuffer.allocate(1024);
		byteBuffer1.put(str.getBytes());
		byteBuffer2.put(str2.getBytes());
		byteBuffer1.flip();
		byteBuffer2.flip();
		ByteBuffer[] arr = { byteBuffer1, byteBuffer2 };
		// 向缓冲区中放入数据时position会改变,因此用flip方法将缓冲区位置值0
		
		Long msg = writeChannel.write(arr);

		System.out.println("写入的字节数" + msg);

	}
	控制台输出:
	写入的字节数6
 (5)通道传输
          通道传输包括两种,一种是当前通道从其他通道中获取数据,一种是当前通道向另一通道传输数据。通道传输是将文件中的数据从一个文件直接传到另一个通道。代码如下:
public static void main(String[] args) throws IOException {
		File from = new File("D:\\from.txt");
		File to = new File("D:\\to.txt");
		FileInputStream in = new FileInputStream(from);
		FileOutputStream out = new FileOutputStream(to);
		 //nioRead(in);
		//nioWrite(out);
		//nioReadFensan(in);
		//nioWriteJuce(out); 
		RandomAccessFile fromR = new RandomAccessFile(from, "rw");
		RandomAccessFile toR = new RandomAccessFile(to, "rw");
		transFrom(fromR,toR);
		transTo(fromR,toR);	
	}
	/**
	 * 通道传输,回直接将from文件中的数据传输到to的文件中去
	 * @param from
	 * @param to
	 * @throws IOException 
	 */
	public static void transFrom(RandomAccessFile from,RandomAccessFile to) throws IOException{
		FileChannel fromChannel = from.getChannel();
		FileChannel toChannel = to.getChannel();
		
	 Long a = toChannel.transferFrom(fromChannel, 0, fromChannel.size());
	 System.out.println("传入的字节数" + a);
		
		
	}
	/**
	 * 通道传输,回直接将from文件中的数据传输到to的文件中去
	 * @param from
	 * @param to
	 * @throws IOException 
	 */
	public static void transTo(RandomAccessFile from,RandomAccessFile to) throws IOException{
		FileChannel fromChannel = from.getChannel();
		FileChannel toChannel = to.getChannel();
		
	 Long a = fromChannel.transferTo(0, fromChannel.size(), toChannel);
	 System.out.println("传入的字节数" + a);	
	}
	控制台输出:
	传入的字节数11
    传入的字节数11
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值