一、什么是Channel

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

二、Buffer和Channel之间的关系

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

NIO编程中的Channel和FileChannel是做什么的?NIO编程中的Channel和FileChannel是做什么的(1)

三、FileChannel

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

NIO编程中的Channel和FileChannel是做什么的?NIO编程中的Channel和FileChannel是做什么的(2)

四、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(); } }

,