Channel是一个通道,可以通过它读取和写入数据,它就像自来水管一样,网络数据通过Channel读取和写入。通道与流的不同之处在于通道是双向的,流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类),而且通道可以用于读、写或者同事用于读写。因为Channel是全双工的,所以它可以比流更好地映射底层操作系统的API。特别是在UNIX网络编程模型中,底层操作系统的通道都是全双工的,同时支持读写操作。
二、Buffer和Channel之间的关系Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
三、FileChannel
FileChannel类可以实现常用的read,write以及scatter/gather操作,同时它也提供了很多专用于文件的新方法。这些方法中的许多都是我们所熟悉的文件操作方法。
四、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();
}
}
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();
}
}