NIO编程中的Channel和FileChannel是做什么的

一、什么是Channel

Channel是一个通道,可以通过它读取和写入数据,它就像自来水管一样,网络数据通过Channel读取和写入。通道与流的不同之处在于通道是双向的,流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类),而且通道可以用于读、写或者同事用于读写。由于Channel是全双工的,所以它可以比流更好地映射底层操作系统的API。特别是在UNIX网络编程模型中,底层操作系统的通道都是全双工的,同时支持读写操作。

二、Buffer和Channel之间的关系

Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

NIO编程中的Channel和FileChannel是做什么的

三、FileChannel

FileChannel类可以实现常用的read,write以及scatter/gather操作,同时它也提供了许多专用于文件的新方法。这些方法中的许多都是我们所熟悉的文件操作方法。

NIO编程中的Channel和FileChannel是做什么的

四、FileChannelDemo

public class FileChannelDemo {

	public static void main(String[] args) throws Exception {
		// 构造一个传统的文件输出流
		FileOutputStream out = new FileOutputStream(
				"/Users/long/demo.txt");
		// 通过文件输出流获取到对应的FileChannel,以NIO的方式来写文件
		FileChannel channel = out.getChannel();
	
		ByteBuffer buffer = ByteBuffer.wrap("程序员阿龙".getBytes());
		channel.write(buffer);
		
		channel.close();
		out.close();
	}
}

五、FileChannel如何实现磁盘文件随机写

public class FileChannelDemo {

	public static void main(String[] args) throws Exception {
		// 构造一个传统的文件输出流
		FileOutputStream out = new FileOutputStream(
				"/Users/long/demo.txt");
		// 通过文件输出流获取到对应的FileChannel,以NIO的方式来写文件
		FileChannel channel = out.getChannel();
	
		ByteBuffer buffer = ByteBuffer.wrap("hello world".getBytes());
		channel.write(buffer);
		// channel会从buffer的position = 0的位置开始读起
    // 一直读到limit,limit = 字符串字节数组的长度
		System.out.println(buffer.position()); 
		System.out.println(channel.position()); // 当前写到了文件的哪一个位置 
		// 继续往磁盘文件里写,相当于文件末尾追加
		
		// 如果想再次将buffer里的数据通过channel写入磁盘文件
//	buffer.rewind(); // position = 0,重新读一遍
//	channel.write(buffer); // 在文件末尾追加写的方式,顺序写
		
		// 把一段数据插入到磁盘文件的中间,磁盘随机写
		// 在文件的随机的位置写入数据
		// 肯定是要再次从buffer中读取数据,所以position必须复位
		buffer.rewind();
		
		// 其次如果你要基于FileChannel随机写,可以调整FileChannel的position
    // 从position位置为6的地方开始写,如果之前有数据则会覆盖
		channel.position(6);
		channel.write(buffer);
		
		channel.close();
		out.close();
	}
	
}

六、线程安全

FileChannel对象是线程安全(thread-safe)的。多个进程可以在同一个实例上并发调用方法而不会引起任何问题,不过并非所有的操作都是多线程的(multithreaded)。影响通道位置或者影响文件大小的操作都是单线程的(single-threaded)。如果有一个线程已经在执行会影响通道位置或文件大小的操作,那么其他尝试进行此类操作之一的线程必须等待。并发行为也会受到底层的操作系统或文件系统影响。

七、FileChannel实现从磁盘文件中读取数据

public class FileChannelDemo {
	
	public static void main(String[] args) throws Exception {
		FileInputStream in = new FileInputStream("/Users/long/demo.txt");
		FileChannel channel = in.getChannel();
	
		ByteBuffer buffer = ByteBuffer.allocateDirect(17);
    // 读数据写入buffer,所以写完后来,buffer的position = 17
		channel.read(buffer);
		
		buffer.flip(); // position = 0,limit = 17
		byte[] data = new byte[17];
		buffer.get(data);
		
		System.out.println(new String(data));  
		
		channel.close();
		in.close();
	}
}
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
僖呜榆徐的头像 - 宋马
评论 共1条

请登录后发表评论