zoukankan      html  css  js  c++  java
  • java NIO FileChannel

    http://www.cnblogs.com/puyangsky/p/5840873.html

    2.2.2 文件通道

    2.2.2.1 打开

    FileChannel只能通过工厂方法来实例化,那就是调用RandomAccessFile、FileInputStream和FileOutputStream的getChannel()方法。如:

    RandomAccessFile file = new RandomAccessFile("a.txt", "r");
    FileChannel fc = file.getChannel();
    2.2.2.2 使用

    先看看FileChannel提供的方法句柄:

    public abstract int read(ByteBuffer dst) throws IOException;//把通道中数据传到目的缓冲区中,dst是destination的缩写
    public abstract int write(ByteBuffer src) throws IOException;//把源缓冲区中的内容写到指定的通道中去

    从句柄可以看出FileChannel是既可以读又可以写的,是全双工的。下面这个例子用来展示FileChannel是如何进行读和写的。

    public class FileChannelTest {
    
        public static void readFile(String path) throws IOException {
            FileChannel fc = new FileInputStream(path).getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(128);
            StringBuilder sb = new StringBuilder();
            while ((fc.read(buffer)) >= 0) {
                //翻转指针
                buffer.flip();
                //remaining = limit - position
                byte[] bytes = new byte[buffer.remaining()];
                buffer.get(bytes);
                String string = new String(bytes, "UTF-8");
                sb.append(string);
    
                //清空buffer
                buffer.clear();
            }
            System.out.println(sb.toString());
        }
    
        public static void writeFile(String path, String string) throws IOException {
            FileChannel fc = new FileOutputStream(path).getChannel();
            ByteBuffer buffer = ByteBuffer.allocate(10);
            int current = 0;
            int len = string.getBytes().length;
            while (current < len) {
                for (int i=0;i<10;i++) {
                    if (current+i>=len) break;
                    buffer.put(string.getBytes()[current+i]);
                }
                current += buffer.position();
    
                buffer.flip();
                fc.write(buffer);
                buffer.clear();
            }
        }
    
    
        public static void main(String[] args) throws IOException {
            String in = "D:/in.txt";
            String out = "D:/out.txt";
            readFile(in);
            writeFile(out, "hello world");
            readFile(out);
        }
    }

    分析一下上面这段代码,在readFile()函数中,通过FileInputStream.getChannel()得到FileChannel对象,并创建ByteBuffer对象,接着利用FileChannel的read方法填充buffer,得到填充完的buffer之后我们将buffer的当前指针翻转一下接着利用buffer的get方法把数据放到byte数组中,接着就可以读取数据了。

    读取文件的整个过程相比原生的I/O方法还是略显麻烦,但是我们如果把数据看成一堆煤矿,把ByteBuffer看成装煤的矿车,而FileChannel看成是运煤的矿道,那么上面的过程就演变成了:先打通一条矿道,然后把煤矿装在小车里运出来。形象的记忆更利于理解这个过程。

    而writeFile()函数也是类似,为了更好的理解Buffer的属性,我特意将buffer的大小设置为10,为要写入的字符串长度为11个字节。首先还是通过FileOutputStream.getChannel()方法得到FileChannel对象,并创建一个10字节大小的缓冲区,接着定义一个整型变量current指向要写入的字符串的当前下标,每次向buffer中put10个字节,并更新current,通过buffer.position()方法可以得到buffer被填充之后指针的位置,也就是缓冲区里的字节个数,然后翻转指针,最后通过FileChannel.write(buffer)方法将buffer写入到文件中。

    同样考虑一下形象化的过程:我们首先把煤矿装入小车(buffer.put()),并打开一条通往矿山的矿道(FileOutputStream.getChannel()),接着把煤矿运输进去(FileChannel.write(buffer))。还是很容易理解的吧!

  • 相关阅读:
    Java debug技术
    mybatis-generator插件
    JVM常见问题
    Java安全之Access control
    JVM新生代各个区的比例问题
    宣告
    退役啦!
    NOIP 2018退役祭
    自定义博客园模板
    带花树算法
  • 原文地址:https://www.cnblogs.com/kakaisgood/p/8856035.html
Copyright © 2011-2022 走看看