zoukankan      html  css  js  c++  java
  • 快速读取大文件的几种方式

    转一篇:http://blog.csdn.net/fengxingzhe001/article/details/67640083

    原来使用一行一行读取文本的方式,速度是慢的的可以,弄了好久还是不行,后来看了下才知道要用字节流传输会快很多

    我自己也测了一下80M的文件,发现给读入块的大小会很明显的影响读入的速度。

    测试代码如下:

    def useBufferIStream(): Util = {
        try {
          val begin = System.currentTimeMillis
          val file = new File(s"E:\data\part-m-00000")
          val fis = new FileInputStream(file)
          val bis = new BufferedInputStream(fis)
          val buffer = new Array[Byte](1024*1024*90)
          var content = ""
          var cnt = 0
          cnt = bis.read(buffer)
          while( cnt != -1) {
            content += new String(buffer, 0, cnt)
            cnt=bis.read(buffer)
          }
    
          bis.close()
          println("=====BufferIStream===== time: " + (System.currentTimeMillis - begin) + "ms")
    
        } catch {
          case e: Exception =>
            // TODO Auto-generated catch block
            e.printStackTrace()
            println("error")
        }
    
      }
    

      代码中绿色部分为读入块的大小,目前设定的是90M大于要读的数据,这时的读入时间只要0.2s

      如果改为10M即(1024*1024*10),读入时间就需要10s左右,速度有很明显的变化。

      这里解释一下一部分代码:

      1、val buffer = new Array[Byte](1024*1024*90)  为每次读入文件的大小;

      2、cnt = bis.read(buffer) 读入数据块大小的标识,如果读入块没用信息则为-1,有信息则为这块信息的大小;

      3、content 为最终读入的文本信息

      4、这里使用的Scala语言,测试中发现

        cnt = bis.read(buffer)
          while( cnt != -1) {
            content += new String(buffer, 0, cnt)
            cnt=bis.read(buffer)
          }

      while的这块语句书写必须用这种形式,不能使用  while((cnt=fis.read(buffer)) != -1)  ,虽然在java上运行是都可以的,但是在Scala中,后者运行会报错,具体原因不明,应该跟Scala的一些机制有关

      上面代码能够解决基本的读取数据问题,但是无法保证数据分块读入时每一行数据是完整的,因此在前文基础上作出部分改动 

      代码如下:(实现将一个86G文件分解为90M的若干小文件,并保证每个小文件中每行数据的完整性)

    def safeCopy():Unit={
    try {
    var size = 0
    var count = 0
    var tmp = -1
    var tmp2 = 0
    var stmp = new Array[Byte](1024*1024*90)
    var content = ""
    val fis = new FileInputStream("E:\data\part-m-00003")
    //val fis = new FileInputStream("E:\data\test\test.txt")
    val bis = new BufferedInputStream(fis)
    val buffer = new Array[Byte](1024*1024*90)
    // val buffer = new Array[Byte](1024)
    size = bis.read(buffer)
    while (size != -1){
    var fos = new FileOutputStream("E:\data\part3\part_"+"%04d".format(count))
    // var fos = new FileOutputStream("E:\data\test\test_"+"%04d".format(count))
    var bos = new BufferedOutputStream(fos)
    tmp = findSize(buffer,size)
    if(tmp>0) {
    if (count != 0) {
    bos.write(stmp, 0, tmp2)
    }
    tmp2 = size - tmp
    Array.copy(buffer, tmp, stmp, 0, tmp2)
    bos.write(buffer, 0, tmp-1)
    }else{
    bos.write(buffer, 0, size)
    }
    size = bis.read(buffer)
    bos.flush()

    println(s"finish $count")
    count+=1
    }
    bis.close()
    println("success!!")
    } catch {
    case e: Exception =>
    e.printStackTrace()
    println ("error!!")
    }
    }

      def findSize(buffer:Array[Byte],size:Int):Int={

    var i=size-1
    // println(size)
    // println(i)
    var j=1
    var num = -1
    while(i>=0 && j==1){
    if(buffer(i)==13 || buffer(i)==10){
    num = i
    j=0
    }
    i-=1
    }
    num+1
    }

      其中,findSize函数负责寻找每块文件中完整数据的长度,buffer(i)==10  其中的10,为换行符的Byte值(每一行数据以换行符作为结束)

    新的方法,发现可以更为容易的解决上述问题

        public static void main(String[] args) throws IOException {
            String inputFile = "E:\data\part-m-00000";
            String outputFile = "E:\data\test01\a-0";
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(inputFile)));
            BufferedReader in = new BufferedReader(new InputStreamReader(bis,"utf-8"),60*1024*1024);
            FileWriter fw=new FileWriter(outputFile);
            int count = 0;
            int count1 = 0;
            Long start = System.currentTimeMillis();
            while(in.ready()){
                String line = in.readLine();
                count++;
                fw.append(line+"
    ");
                if(count == 150000){
                    count1++;
                    fw.flush();
                    fw.close();
                    fw = new FileWriter("E:\data\test01\a-"+count1);
                    count =0;
                    Long end = System.currentTimeMillis();
                    System.out.println((end-start));
                    start = System.currentTimeMillis();
                }
    
            }
            in.close();
            fw.flush();
            fw.close();
        }
    

      速度与前面不相上下,并且可以很好地解决按条读取的需求,大小通过控制条数的多少来实现。

  • 相关阅读:
    2013-05-25 14:04 zend studio10正式版如何汉化?
    网页前端优化之滚动延时加载图片
    appium框架之bootstrap
    软件测试面试题(一)
    Java中的经典算法之冒泡排序(Bubble Sort)
    Git知识总览(一) 从 git clone 和 git status 谈起
    Webdriver获取多个元素
    idea注册码到期,破解idea
    安装appium桌面版和命令行版
    Python+Appium学习篇之WebView处理
  • 原文地址:https://www.cnblogs.com/LazyJoJo/p/7610791.html
Copyright © 2011-2022 走看看