• FileChannel按行读取文件


    FileChannel是什么

    它是用于读取、写入、映射和操作文件的通道。除了熟悉的字节通道读取,写入和关闭操作之外,此类还定义了以下特定于文件的操作:

    • 可以以不影响通道当前位置的方式在文件中的绝对位置读取或写入字节。

    • 文件的区域可以直接映射到内存中。 对于大文件,这通常比调用通常的读取或写入方法要有效得多。

    • 对文件所做的更新可能会被强制发送到基础存储设备,以确保在系统崩溃时不会丢失数据。

    • 字节可以从文件传输到其他通道,反之亦然,可以通过许多操作系统进行优化,将字节快速传输到文件系统缓存或直接从文件系统缓存传输。

    • 文件的区域可能被锁定,以防止其他程序访问。

    FileChannel配合着ByteBuffer,将读写的数据缓存到内存中,然后以批量/缓存的方式read/write,省去了非批量操作时的重复中间操作,操纵大文件时可以显著提高效率。ByteBuffer可以使用直接内存(系统内存)(allocateDirect),使用后无需jvm回收。

    总结一下,按照字节读取,对大文件读取效率更高,无法设置为非阻塞模式,它总是运行在阻塞模式下。

    但有时候我们要按照行读取文件,而FileChannel只能按照字节读取,所以这里需要对换行进行判断一下,在这里我对其进行了实现,供大家参考。

    实现

    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class test1 {
        public static void readLineByChannel(String path) throws IOException {
            long lineNumber = 0;
            FileInputStream fileIn = new FileInputStream(path);
            FileChannel fileChannel = fileIn.getChannel();
            // 开始按行读取
            int bufferSize = 1024 * 1024;  // 每一块的大小
            ByteBuffer buffer = ByteBuffer.allocate(bufferSize);
            byte b;
    
            while(fileChannel.read(buffer) > 0)
            {
                buffer.flip();
                for (int i = 0; i < buffer.limit(); i++)
                {
                    b = buffer.get();
                    if(b==10){  // 如果遇到换行
                        lineNumber++;
                    }
    
                }
                buffer.clear(); // 清空buffer
            }
            fileChannel.close();
            System.out.println(lineNumber);
        }
    
        public static void readLineByBufferedReader(String path) throws IOException {
            long lineNumber = 0;
            FileInputStream inputStream = new FileInputStream(path);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            String line;
            while((line=bufferedReader.readLine()) != null)
            {
                lineNumber++;
            }
            inputStream.close();
            bufferedReader.close();
    
            System.out.println(lineNumber);
        }
    
        public static void main(String[] args) throws IOException {
            String path = "大文件";
            long startTime = System.currentTimeMillis();
            readLineByChannel(path);
            System.out.println("readLineByChannel耗时:" + (System.currentTimeMillis() - startTime));
            startTime = System.currentTimeMillis();
            readLineByBufferedReader(path);
            System.out.println("readLineByBufferedReader耗时:" + (System.currentTimeMillis() - startTime));
        }
    }
    

    使用FileChannelBufferedReader分别的对大文件进行读取,并且计算有多少行。

    //第一次测试:
    169860474
    readLineByChannel耗时:27310
    169860474
    readLineByBufferedReader耗时:24944
        
    //第二次测试
    169860474
    readLineByChannel耗时:28677
    169860474
    readLineByBufferedReader耗时:21229
    

    测试文件12GB,可以看出文件有1亿6千多万行,实际测试下来两者差距不大,甚至BufferedReader还快点。

  • 相关阅读:
    Android导入自定义的jar包时出现 E/AndroidRuntime(486): java.lang.NoClassDefFoundError错误
    cocos2d-x认识之旅
    ASP.Net MVC Filter验证用户登录
    RHEL6安装调试过程中遇到的问题集
    java8新增特性(二)----函数式接口(Functional)
    京东云、新浪微博等专家畅谈Docker未来格局:开放与竞争(上)
    Activity启动模式的深入分析
    ShopEx 中规格属性添加时,自己主动计算其相应的销售价格,同一时候注意模板中的变量间的计算
    【天气APP】之桌面时钟witget组件
    xcode6.3 模版位置
  • 原文地址:https://www.cnblogs.com/harrylyx/p/13172893.html
Copyright © 2020-2023  润新知