快速读取大文件的几种方式

快速读取大文件的几种方式

转一篇: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+"\n");

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();

}

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

相关推荐

Java中什么是方法的重载
盒子365靠谱吗

Java中什么是方法的重载

📅 07-11 👁️ 1861
有一种燕麦叫莜麦,有一种大麦叫青稞,附我国小麦的地理分布和生产特点
酷派B770怎么样 好用么 酷派B770好不好 值得买么
盒子365靠谱吗

酷派B770怎么样 好用么 酷派B770好不好 值得买么

📅 01-19 👁️ 6803