Java NIO Channel之FileChannel [ 转载 ]

Java NIO Channel之FileChannel [ 转载 ]

@author zachary.guo

对于文件 I/O,最强大之处在于异步 I/O(asynchronous I/O),它允许一个进程可以从操作系统请求一个或多个 I/O 操作而不必等待这些操作的完成。发起请求的进程之后会收到它请求的 I/O 操作已完成的通知。异步 I/O 是一种高级性能,当前的很多操作系统都还不具备。因此,文件通道在多数情况下来说总是阻塞式的,因此不能被置于非阻塞模式。

FileChannel 对象不能直接创建。一个 FileChannel 实例只能通过在一个打开的 File 对象(RandomAccessFile、FileInputStream 或 FileOutputStream)上调用 getChannel() 方法获取。调用 getChannel() 方法会返回一个连接到相同文件的 FileChannel 对象且该 FileChannel 对象具有与 File 对象相同的访问权限,然后你就可以使用通道对象来利用强大的 FileChannel API了:

Java代码  

  1. package java.nio.channels;
  2. public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
  3. // This is a partial API listing
  4. // All methods listed here can throw java.io.IOException
  5. public abstract int read(ByteBuffer dst, long position);
  6. public abstract int write(ByteBuffer src, long position);
  7. public abstract long size();
  8. // 返回当前文件的 position 值。返回值是一个长整型(long),表示文件中的当前字节位置。
  9. public abstract long position();
  10. // 将通道的 position 设置为指定值。负值,将异常伺候;值可以超过文件尾,这会导致文件空洞。
  11. public abstract void position(long newPosition);
  12. public abstract void truncate(long size);
  13. public abstract void force(boolean metaData);
  14. public final FileLock lock();
  15. public abstract FileLock lock(long position, long size, boolean shared);
  16. public final FileLock tryLock();
  17. public abstract FileLock tryLock(long position, long size, boolean shared);
  18. public abstract MappedByteBuffer map(MapMode mode, long position, long size);
  19. public abstract long transferTo(long position, long count, WritableByteChannel target);
  20. public abstract long transferFrom(ReadableByteChannel src, long position, long count);
  21. public static class MapMode {
  22. public static final MapMode READ_ONLY;
  23. public static final MapMode READ_WRITE;
  24. public static final MapMode PRIVATE;
  25. }
  26. }

同大多数通道一样,只要有可能,FileChannel 都会尝试使用本地 I/O 服务。FileChannel 类本身是抽象的,你从 getChannel() 方法获取的实际对象是一个具体子类(subclass)的一个实例(instance),该子类可能使用本地代码来实现以上 API 方法中的一些或全部。

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

◇ 访问文件 
        每个 FileChannel 对象都同一个文件描述符(file descriptor)有一对一的关系,所以上面列出的 API 方法与在你最喜欢的 POSIX(可移植操作系统接口)兼容的操作系统上的常用文件 I/O 系统调用紧密对应也就不足为怪了。

本质上讲,RandomAccessFile 类提供的是同样的抽象内容。在通道出现之前,底层的文件操作都是通过 RandomAccessFile 类的方法来实现的。FileChannel 模拟同样的 I/O 服务,因此它的 API 自然也是很相似的。


                                                                    File I/O API 比较

同底层的文件描述符一样,每个 FileChannel 都有一个叫 “file position”的概念。这个 position 值决定文件中哪一处的数据接下来将被读或者写。因此,FileChannel 位置(position)是从底层的文件描述符获得的,该 position 同时被作为通道引用获取来源的文件对象共享。这也就意味着一个对象对该 position 的更新可以被另一个对象看到:

Java代码  

  1. RandomAccessFile randomAccessFile = new RandomAccessFile ("filename", "r");
  2. // Set the file position
  3. randomAccessFile.seek (1000);
  4. // Create a channel from the file
  5. FileChannel fileChannel = randomAccessFile.getChannel( );
  6. // This will print "1000"
  7. System.out.println ("file pos: " + fileChannel.position( ));
  8. // Change the position using the RandomAccessFile object
  9. randomAccessFile.seek (500);
  10. // This will print "500"
  11. System.out.println ("file pos: " + fileChannel.position( ));
  12. // Change the position using the FileChannel object
  13. fileChannel.position (200);
  14. // This will print "200"
  15. System.out.println ("file pos: " + randomAccessFile.getFilePointer( ));

尝试在文件末尾之外的 position 进行一个绝对 read() 操作,size() 方法会返回一个 end-of-file。在超出文件大小的 position 上做一个绝对 write() 会导致文件增加以容纳正在被写入的新字节。文件中位于之前 end-of-file 位置和新添加的字节起始位置之间区域的字节的值不是由 FileChannel 类指定,而是在大多数情况下反映底层文件系统的语义。不过,大部分情况下,这些空洞会被填 0。

当需要减少一个文件的 size 时,truncate() 方法会砍掉您所指定的新 size 值之外的所有数据。如果当前 size 大于新 size,超出新 size 的所有字节都会被悄悄地丢弃。如果提供的新 size 值大于或等于当前的文件 size 值,该文件不会被修改。这两种情况下,truncate() 都会产生副作用:文件的 position 会被设置为所提供的新 size 值。

上面列出的最后一个 API 是 force()。该方法告诉通道强制将全部待定的修改都应用到磁盘的文件上。所有的现代文件系统都会缓存数据和延迟磁盘文件更新以提高性能。调用 force() 方法要求文件的所有待定修改立即同步到磁盘。

◇ 文件空洞 
        文件位移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中但没有写过的字节都被设为 0。

如果 offset 比文件的当前长度更大,下一个写操作就会把文件“撑大(extend)”。这就是所谓的在文件里创造“空洞(hole)”。没有被实际写入文件的所有字节由重复的 0 表示。空洞是否占用硬盘空间由文件系统(file system)决定。

时间: 2024-10-15 06:52:07

Java NIO Channel之FileChannel [ 转载 ]的相关文章

Java NIO Channel [ 转载 ]

Java NIO Channel [ 转载 ] @author Java NIO系列教程(二) Channel Java NIO的通道类似流,但又有些不同: 既可以从通道中读取数据,又可以写数据到通道.但流的读写通常是单向的. 通道可以异步地读写. 通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入. 正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道.如下图所示: Channel的实现 这些是Java NIO中最重要的通道的实现: FileChannel D

Java NIO Channel

Java Nio 1 Java NIO Tutorial 2 Java NIO Overview 3 Java NIO Channel 4 Java NIO Buffer 5 Java NIO Scatter / Gather 6 Java NIO Channel to Channel Transfers 7 Java NIO Selector 8 Java NIO FileChannel 9 Java NIO SocketChannel 10 Java NIO ServerSocketChan

Java NIO Channel to Channel Transfers

Java Nio 1 Java NIO Tutorial 2 Java NIO Overview 3 Java NIO Channel 4 Java NIO Buffer 5 Java NIO Scatter / Gather 6 Java NIO Channel to Channel Transfers 7 Java NIO Selector 8 Java NIO FileChannel 9 Java NIO SocketChannel 10 Java NIO ServerSocketChan

JAVA NIO 内存映射(转载)

原文地址:http://blog.csdn.net/fcbayernmunchen/article/details/8635427 Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理. 在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数 read().write() ,此时调用此函数的进程(在JAVA中即java进程)由当

【JAVA】【NIO】6、Java NIO Channel to Channel Transfers

在Java NIO中,如果其中有一个channel是FileChannel,你可以直接将数据从一个channel传递到另一个channel.FileChannel类有一个transferTo和一个transferFrom方法可以做到. transferFrom() 该方法将数据从一个源channel传递到FileChannel. 实例: 参数position和count,表明在目标文件中,从哪个位置开始写,最大传输多少字节(count)数据.如果源channel里的数据少于count字节,那么传

【JAVA】【NIO】3、Java NIO Channel

Java NIO和流量相似,但有些差异: ·通道可读写,流仅支持单向.读或写 ·异步通道读取 ·通道读写器,他们是和Buffer交替 道的实现 下面是Java NIO中最重要的通道的实现: ·FileChannel ·DatagramChannel ·SocketChannel ·ServerSocketChannel FileChannel从文件读数据或写进文件 DatagramChannel通过UDP在网络上读写数据 SocketChannel通过TCP在网络上读写数据 ServerSock

Java NIO FileChannel

Java NIO中的FileChannel是一个连接到文件的通道.可以通过文件通道读写文件. FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下. 打开FileChannel 在使用FileChannel之前,必须先打开它.但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream.OutputStream或RandomAccessFile来获取一个FileChannel实例.下面是通过RandomAccessFile打开FileChannel的示例

Java NIO系列教程(七) FileChannel

Java NIO中的FileChannel是一个连接到文件的通道.可以通过文件通道读写文件. FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下. 打开FileChannel 在使用FileChannel之前,必须先打开它.但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream.OutputStream或RandomAccessFile来获取一个FileChannel实例.下面是通过RandomAccessFile打开FileChannel的示例

Java NIO (2) Channel

Java NIO Channel Java NIO Channels are similar to streams with a few differences: You can both read and write to a Channels. Streams are typically one-way (read or write). Channels can be read and written asynchronously. Channels always read to, or w