zoukankan      html  css  js  c++  java
  • 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还快点。

  • 相关阅读:
    【Azure 应用服务】App Service中运行Python 编写的 Jobs,怎么来安装Python包 (pymssql)呢?
    【Azure 存储服务】使用POST方式向Azure Storage Queue中插入Message的办法
    【Azure Developer】使用Azure Resource Graph的查询语法的示例
    img标签到底是行内元素还是块级元素
    [前端面试]前端缓存问题看这篇,让面试官爱上你
    Vue3.0 响应式数据原理:ES6 Proxy
    几行代码教你解决微信生成海报及二维码
    冷门的HTML
    HTML选择器
    程序猿必备 代码保平安
  • 原文地址:https://www.cnblogs.com/harrylyx/p/13172893.html
Copyright © 2011-2022 走看看