FileChannel的深入理解

一,官方描述


    一个读,写,映射,操作文件的通道。

    文件通道有可以被查询和修改的一个当前位置,文件本身包含了一个可悲读写的变长字节序列,并且它的当前的size会被查询。当被写入的字节超过当前文件的大
小时,文件的大小会增加;当文件被截断的时候,文件的大小会减少。文件有一个写被关联的像权限,内容类型和最后修改时间的元数据;这个类没有定义访问元数
据的方法。

    此外对于熟悉的字节通道读写关闭操作,这个类定义了以下的特定文件操作:

    1.在文件的绝对位置的字节读写操作在某种程度上不会影响通道的当前位置。

    2.文件的区域可能会被直接映射到内存中,对于大文件来说,这比通常的读写方法更有效。

    3.为了保证数据在系统崩溃之后不丢失数据,文件的修改模式会被强制到底层存储设备。

    4.字节能从一个文件被转换为一些其他的通道,反之亦然,这种操作在某种程度上会被许多操作系统或者文件系统优化成一个非常快速的直接传输。

    5.文件的区域也许会被锁住来防止其它程序的访问。

   

文件通道在多线程下是安全的,close方法能在任何时候被调用,这个方法在接口Channel中被指定。在任何时间,只有涉及到通道的position
和改变它的文件的size的过程中的操作,当第一个这样的方法在处理中时尝试初始化第二个这样的操作将被阻塞,知道第一个操作完成。其它的操作,特别是显
式的获取position,会被同步处理;它们是否事实上做了同步,这样以来于底层操作系统的实现,因此是未特别指定的。

    文件的视图通过这个类的实例被提供,这个视图确保跟在相同程序中的被其它实例提供的相同文件视图的一致性。这个类的实例也许会也许不会提供视图,通过其他的
同步程序保持视图的可见性,应归于被执行的底层操作系统和网络文件系统延迟的引导的缓存。不管语言在其它程序中写,这是事实,而且不管它们运行在相同的机
器上还是不同的机器上,
任何这样的不一致的确切性质是依赖于系统,因此,未特指。

    这个类没有定义打开文件或者创建一个新文件的方法;这些方法也许在未来的发行版中被添加。像这样的文件通道可以通过
FileInputStream,FileOutputStream,RandomAccessFile类中的getChannel方法获得,这个
getChannel返回的文件通道是被连接到相同的底层文件的。

    文件通道的状态与通过getChannel方法返回的channel对象是紧密相连的,如果明确的改变文件通道的position或者读写字节,则会改变原
始对象的文件position,反之亦然。通过文件通道改变文件通道的长度将改变原始对象的文件长度,反之亦然。改变文件通道的内容也会改变原始对象的文
件内容,反之亦然。

    这个类指定了个别的指针,像“只读打开”,“只写打开”,“读写打开”。通过FileInputStream的getChannel方法获取的文件通道是只
读的,当然通过FileOutputStream的getChannel的方法获取的文件通道是可写的,通过RandomAccessFile的
getChannel的方法获取的文件通道,在创建时如果传递的参数是“r",则为只读,否则为”读写“或者“写”。

    文件通道也许在追加模式下被打开,
例如它的获得是通过一个给FileOutputStream(boolean)或者FileOutputStream(FIle,boolean)传递参
数true时,则这个通道是在追加模式下。在这种模式下,每个相对写方法的调用操作首先会把position增长到文件尾部,然后写入被请求的数据。是否
文件position的增长和数据的写入在原子操作下被完成是依赖于操作系统的,并为特指。


二,源码分析


FileChannel这个类是继承于抽象类AbstractInterruptibleChannel,实现了接口ByteChannel,GatheringByteChannel,ScatteringByteChannel。

由于这个类的实现类FileChannelImpl没有被提供源码,因此,在JDK中是看不到的,想看源码,猛击这里FileChannelImpl。

至于源码分析,博主看了几个小时也没看出个门道来,太复杂,而且又接近底层,博主现在还没能力分析源码,所以就不分析了,有志向一探究竟的,大家可以自己去看看啊。

三,实例


package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelTest {
    private static final String outputPath = "output.txt";
    private static String data = "你好,我是张三
我今天很开心和你约会
请多多指教";
    public static void main(String[] args) throws IOException {
        File inputFile = new File(outputPath);
        File outputFile = new File(outputPath);
        if(!inputFile.exists()) {
            inputFile.createNewFile();
        }
        if(!outputFile.exists()) {
            outputFile.createNewFile();
        }
        //实例化输入输出流,并且获取相对应的FileChannel实例
        FileInputStream fis = new FileInputStream(inputFile);
        FileChannel inputChannel = fis.getChannel();
        FileOutputStream fos = new FileOutputStream(outputFile);
        FileChannel outputChannel = fos.getChannel();
        //获取数据的字节数组
        byte[] outputBuffer = data.getBytes();
        //分配一个字节缓冲(这个类在下一篇中介绍)
        ByteBuffer obb = ByteBuffer.allocate(1024);
        //将字节数组读入字节缓冲中
        obb.put(outputBuffer);
        obb.flip();  //调用该方法表示开始读取字节缓冲中的数据,即limit=position,position=0
        //将字节写入文件中
        int n = outputChannel.write(obb);
        outputChannel.close();  //关闭通道
        System.out.println("output n is " + n);
        fos.close();  //关闭输出流
        //再分配一个字节缓冲
        ByteBuffer ibb = ByteBuffer.allocate(1024);
        //将数据从通道中读入字节缓冲中
        int in = inputChannel.read(ibb);
        //初始化一个字节数组,这个字节数组的长度不能大于这个字节缓冲的limit-position的长度,不然会抛出java.nio.BufferUnderflowException
        byte[] inputBuffer = new byte[ibb.position()];
        //准备从字节缓冲中读取数据
        ibb.flip();
        System.out.println("input n is " + in);
        //将数据读入字节数组中
        ibb.get(inputBuffer);
        System.out.println(new String(inputBuffer));
        inputChannel.close();
        fis.close();
    }

}


你可能感兴趣的:(java,nio)