内容目录
3.3 文件通道
直到现在,我们都还只是在泛泛地讨论通道,比如讨论那些对所有通道都适用的内容。是时候具体点了,本节我们来讨论文件通道(socket 通道将在下一节讨论)。从图 3-7 可以发现,FileChannel
类可以实现常用的 read,write以及scatter/gather操作,同时它也提供了很多专用于文件的新方法。这些方法中的许多都是我们所熟悉的文件操作,不过其他的您可能之前并未接触过。现在我们将在此对它们全部予以讨论。
文件通道总是阻塞式的,因此不能被置于非阻塞模式。现代操作系统都有复杂的缓存和预取机制,使得本地磁盘 I/O 操作延迟很少。网络文件系统一般而言延迟会多些,不过却也因该优化而受益。面向流的 I/O 的非阻塞范例对于面向文件的操作并无多大意义,这是由文件 I/O 本质上的不同性质造成的。对于文件 I/O,最强大之处在于异步 I/O(asynchronous I/O),它允许一个进程可以从操作系统请求一个或多个 I/O 操作而不必等待这些操作的完成。发起请求的进程之后会收到它请求的 I/O 操作已完成的通知。异步 I/O 是一种高级性能,当前的很多操作系统都还不具备。以后的NIO 增强也会把异步 I/O 纳入考虑范围。
我们在3.1.1节中提到,FileChannel
对象不能直接创建。一个FileChannel
实例只能通过在一个打开的file对象(RandomAccessFile
、FileInputStream
或FileOutputStream
)上调用getChannel()
方法获取 。调用getChannel()
方法会返回一个连接到相同文件的FileChannel
对象且该FileChannel
对象具有与file对象相同的访问权限,然后您就可以使用该通道对象来利用强大的FileChannel API了:
package java.nio.channels;
public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel{
// 这里仅列出部分API
// 所有可能抛出java.io.IOException异常的方法均在此处列出
public abstract int read (ByteBuffer dst, long position)
public abstract int write (ByteBuffer src, long position)
public abstract long size()
public abstract long position()
public abstract void position(long newPosition)
public abstract void truncate(long size)
public abstract void force(boolean metaData)
public final FileLock lock()
public abstract FileLock lock(long position, long size, boolean shared)
public final FileLock tryLock()
public abstract FileLock tryLock (long position, long size, boolean shared)
public abstract MappedByteBuffer map (MapMode mode, long position, long size)
public static class MapMode{
public static final MapMode READ_ONLY
public static final MapMode READ_WRITE
public static final MapMode PRIVATE
}
public abstract long transferTo (long position, long count, WritableByteChannel target)
public abstract long transferFrom (ReadableByteChannel src, long position, long count)
}
上面的代码中给出了FileChannel
类引入的新 API 方法。所有这些方法都可以抛出java.io.IOException
异常,不过抛出语句并未在此列出。
JSR 51 也定义了对于一个扩展的文件系统接口 API 的需求。JDK 1.4 版本中尚未实现该 API,不过JDK 1.5 版本中有望实现。一旦此改进的文件系统 API 就位,它将很可能成为FileChannel对象首选的来源。
同大多数通道一样,只要有可能,FileChannel
都会尝试使用本地 I/O 服务。FileChannel
类本身是抽象的,您从getChannel()
方法获取的实际对象是一个具体子类(subclass)的一个实例(instance),该子类可能使用本地代码来实现以上 API 方法中的一些或全部。
FileChannel
对象是线程安全(thread-safe)的。多个进程可以在同一个实例上并发调用方法而不会引起任何问题,不过并非所有的操作都是多线程的(multithreaded)。影响通道位置或者影响文件大小的操作都是单线程的(single-threaded)。如果有一个线程已经在执行会影响通道位置或文件大小的操作,那么其他尝试进行此类操作之一的线程必须等待。并发行为也会受到底层的操作系统或文件系统影响。
同大多数 I/O 相关的类一样,FileChannel
是一个反映Java虚拟机外部一个具体对象的抽象。FileChannel
类保证同一个Java虚拟机上的所有实例看到的某个文件的视图均是一致的,但是Java虚拟机却不能对超出它控制范围的因素提供担保。通过一个FileChannel
实例看到的某个文件的视图同通过一个外部的非Java进程看到的该文件的视图可能一致,也可能不一致。多个进程发起的并发文件访问的语义高度取决于底层的操作系统和(或)文件系统。一般而言,由运行在不同Java虚拟机上的FileChannel
对象发起的对某个文件的并发访问和由非 Java 进程发起的对该文件的并发访问是一致的。
0 条评论
撰写评论