zoukankan      html  css  js  c++  java
  • java处理大文本2G以上

    面试中经常碰到类似问题,问题的关键我觉得是用设置一个缓冲区

    还有一个思路 是通过Linux split 命令将文件直接切割成小文件,再进行处理再汇总。

    或者jdk7提供的 forkjoin 框架,利用forkjoinpool管理的线程池,处理此种问题,未尝试过。

    以下内容转自: http://blog.csdn.net/sysmedia/article/details/78030113

     

    如下的程序,将一个行数为fileLines的文本文件平均分为splitNum个小文本文件,其中换行符'r'是linux上的,windows的java换行符是' ':

    复制代码
    package kddcup2012.task2.FileSystem;  
      
    import java.io.BufferedInputStream;  
    import java.io.BufferedReader;  
    import java.io.File;  
    import java.io.FileInputStream;  
    import java.io.FileWriter;  
    import java.io.IOException;  
    import java.io.InputStreamReader;  
      
    public class FileSplit  
    {     
        public static void main(String[] args) throws IOException  
        {  
            long timer = System.currentTimeMillis();  
            int bufferSize = 20 * 1024 * 1024;//设读取文件的缓存为20MB   
              
            //建立缓冲文本输入流   
            File file = new File("/media/Data/毕业设计/kdd cup/数据/userid_profile.txt");  
            FileInputStream fileInputStream = new FileInputStream(file);  
            BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);  
            InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream);  
            BufferedReader input = new BufferedReader(inputStreamReader, bufferSize);  
              
            int splitNum = 112-1;//要分割的块数减一   
            int fileLines = 23669283;//输入文件的行数   
            long perSplitLines = fileLines / splitNum;//每个块的行数   
            for (int i = 0; i <= splitNum; ++i)  
            {  
                //分割   
                //每个块建立一个输出   
                FileWriter output = new FileWriter("/home/haoqiong/part" + i + ".txt");  
                String line = null;  
                //逐行读取,逐行输出   
                for (long lineCounter = 0; lineCounter < perSplitLines && (line = input.readLine()) != null; ++lineCounter)  
                {  
                    output.append(line + "
    ");  
                }  
                output.flush();  
                output.close();  
                output = null;  
            }  
            input.close();  
            timer = System.currentTimeMillis() - timer;  
            System.out.println("处理时间:" + timer);  
        }  
    }  
    复制代码

     

    以上程序处理大文本文件只需要30MB左右的内存空间(这和所设的读取缓冲大小有关),但是速度不是很快,在磁盘没有其他程序占用的情况下,将200MB文件分割为112份需要20秒(机器配置:Centrino2 P7450 CPU,2GB DDR3内存,Ubuntu 11.10系统,硬盘最大读写速度大约60MB/S)。

    另外,对于几百兆到2GB大小的文件,使用内存映射文件的话,速度会块一些,但是内存映射由于映射的文件长度不能超过java中int类型的最大值,所以只能处理2GB以下的文件。

     

    java 读取一个巨大的文本文件既能保证内存不溢出又能保证性能  
     
    复制代码
    package helloword.helloword;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.RandomAccessFile;
    import java.nio.ByteBuffer;
    import java.nio.MappedByteBuffer;
    import java.nio.channels.FileChannel;
    
    public class ReadBig {
        public static String fff = "C:\mq\read\from.xml";
    
        public static void main1(String[] args) throws Exception {
    
            final int BUFFER_SIZE = 0x300000;// 缓冲区大小为3M
    
            File f = new File(fff);
    
            MappedByteBuffer inputBuffer = new RandomAccessFile(f, "r").getChannel().map(FileChannel.MapMode.READ_ONLY,
                    f.length() / 2, f.length() / 2);
    
            byte[] dst = new byte[BUFFER_SIZE];// 每次读出3M的内容
    
            long start = System.currentTimeMillis();
    
            for (int offset = 0; offset < inputBuffer.capacity(); offset += BUFFER_SIZE) {
    
                if (inputBuffer.capacity() - offset >= BUFFER_SIZE) {
    
                    for (int i = 0; i < BUFFER_SIZE; i++)
    
                        dst[i] = inputBuffer.get(offset + i);
    
                } else {
    
                    for (int i = 0; i < inputBuffer.capacity() - offset; i++)
    
                        dst[i] = inputBuffer.get(offset + i);
    
                }
    
                int length = (inputBuffer.capacity() % BUFFER_SIZE == 0) ? BUFFER_SIZE
                        : inputBuffer.capacity() % BUFFER_SIZE;
    
                System.out.println(new String(dst, 0, length));// new
                // String(dst,0,length)这样可以取出缓存保存的字符串,可以对其进行操作
    
            }
    
            long end = System.currentTimeMillis();
    
            System.out.println("读取文件文件一半内容花费:" + (end - start) + "毫秒");
    
        }
    
        public static void main2(String[] args) throws Exception {
            int bufSize = 1024;
            byte[] bs = new byte[bufSize];
            ByteBuffer byteBuf = ByteBuffer.allocate(1024);
            FileChannel channel = new RandomAccessFile(fff, "r").getChannel();
            while (channel.read(byteBuf) != -1) {
                int size = byteBuf.position();
                byteBuf.rewind();
                byteBuf.get(bs); // 把文件当字符串处理,直接打印做为一个例子。
                System.out.print(new String(bs, 0, size));
                byteBuf.clear();
            }
    
        }
    
        public static void main3(String[] args) throws Exception {
            BufferedReader br = new BufferedReader(new FileReader(fff));
            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        }
    
        public static void main(String[] args) throws Exception {
            int bufSize = 1024;
            byte[] bs = new byte[bufSize];
            ByteBuffer byteBuf = ByteBuffer.allocate(1024);
            FileChannel channel = new RandomAccessFile("d:\filename", "r").getChannel();
            while (channel.read(byteBuf) != -1) {
                int size = byteBuf.position();
                byteBuf.rewind();
                byteBuf.get(bs);
                // 把文件当字符串处理,直接打印做为一个例子。
                System.out.print(new String(bs, 0, size));
                byteBuf.clear();
            }
        }
    
    }
    复制代码

     

    java 读取大容量文件,内存溢出?怎么按几行读取,读取多次。 最佳答案
    复制代码
    package helloword.helloword;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.RandomAccessFile;
    import java.util.Scanner;
    
    public class TestPrint {
        public static void main(String[] args) throws IOException {
            String path = "你要读的文件的路径";
            RandomAccessFile br = new RandomAccessFile(path, "rw");// 这里rw看你了。要是之都就只写r
            String str = null, app = null;
            int i = 0;
            while ((str = br.readLine()) != null) {
                i++;
                app = app + str;
                if (i >= 100) {// 假设读取100行
                    i = 0;
                    // 这里你先对这100行操作,然后继续读
                    app = null;
                }
            }
            br.close();
        }
    
        // 当逐行读写大于2G的文本文件时推荐使用以下代码
        void largeFileIO(String inputFile, String outputFile) {
            try {
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(inputFile)));
                BufferedReader in = new BufferedReader(new InputStreamReader(bis, "utf-8"), 10 * 1024 * 1024);// 10M缓存
                FileWriter fw = new FileWriter(outputFile);
                while (in.ready()) {
                    String line = in.readLine();
                    fw.append(line + " ");
                }
                in.close();
                fw.flush();
                fw.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
    复制代码
    jdk本身就支持超大文件的读写。
     
    网上的文章基本分为两大类:
    一类是使用BufferedReader类读写超大文件;
    另一类是使用RandomAccessFile类读取,经过比较,最后使用了前一种方式进行超大文件的读取,下面是相关代码,其实很简单
    -------------------------------------------------------------------
    复制代码
    File file = new File(filepath);   
    BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));    
    BufferedReader reader = new BufferedReader(new InputStreamReader(fis,"utf-8"),5*1024*1024);// 用5M的缓冲读取文本文件  
      
    String line = "";
    while((line = reader.readLine()) != null){
       //TODO: write your business
    }
    复制代码
  • 相关阅读:
    树莓派学习笔记(三)——远程调试树莓派程序(Pycharm实现)
    树莓派学习笔记(一)——系统安装与远程显示
    记 laravel 排除CSRF验证
    thinkPHP5 生成微信小程序二维码 保存在本地
    微信小程序 rich-text 富文本中图片自适应
    Laravel 中自定义 手机号和身份证号验证
    laravel Excel 导入
    微信小程序之页面跳转(tabbar跳转及页面内跳转)
    关于MySQL事务和存储引擎常见FAQ
    微信小程序点击保存图片到本地相册——踩坑
  • 原文地址:https://www.cnblogs.com/xifenglou/p/8409031.html
Copyright © 2011-2022 走看看