Java 大文本多线程高效读取

本文介绍 Java多线程读取大文件性能提升的高效方案。


前沿

我们在读取一个正常文件的时候,将使用,BufferedReader.read() 的三种方法:

BufferedReader.read()  单字节,这个效率最低,基本不考了

BufferedReader.read(char[] cbuf)   根据传入 cbuf 的长度,顺序读取。此方法如果单线程的时候,可以考虑,显然多线程不行。

BufferedReader.read(char[] cbuf, int off, int len)  本文中多线程高效读取,需要用到,因为大可以分段读取呀,有个 off 和 len 伙伴们,就是他了!!!


那么我们就来实现把。在实习前我仍然需要在强调两点:

1、InputStream 是个阻塞顺序读取的流对象,也就意味着如果使用多线程是,创建一个全局 InputStream 然后分别传给不同的子线程,且在子线程中进行分段读取,那么恭喜你你中奖了,你会得到很郁闷的结果。结果就是子线程将不能正常分段获取!!!

2、BufferedReader.read(char[] cbuf, int off, int len) 中 

cbuf 为缓冲数组

off 为保存字符的开始位置

len  一次最多读入字符个数

        说明:这里的 off 是个比较郁闷的字段,什么是保存字符的开始位置,笔者在这里进行了验证,当我把 off 以 0传入的时候正常,以 1 传入想从第1个字符截取,也就是线程分段截取的时候,异常就来了。这就麻烦了,如果off 并不是理解上的起始读取位置,那么怎么用多线程分段读取呢???莫慌,且看这里:reader.skip(this.start); 用这个,伙伴们看到这个你们就成功了。

3、伙伴们请注意看,本文中采用的多线程的模式,是假定并不知道文本总长度的情况下进行多线程读取,假定:特殊场景不知道文件总长度!


接下来,话不多说,上代码:

package com.pft.views.webservices.readutil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class ReadUtil {

	private int theadNum = 6 /* 线程数 */, timeReadLine = 2048 /* 子线程一次循环读取字节长度 */, timeForTime = 5; /* 子线程一次循环读取数 */
	private StringBuffer sbf = new StringBuffer();
	
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		
		ReadUtil rUtil = new ReadUtil();
		rUtil.read(new File("D:\\dslrcv.txt"), 0);
		
		System.out.println("获取字符总长度:" + rUtil.getSbf().length() + ". 总耗时:" +(System.currentTimeMillis() - start) + "毫秒!");
	}
	
	/**
	 * 假定:特殊场景不知道文件总长度! 情景下的   递归+多线程   模式。 可通过File得到总长度,此时可更好的进行子线程数的分配和控制。
	 * @param file 文件
	 * @param start 其实位置
	 */
	public void read(File file, int start){
		List<ReadItem> list = new ArrayList<ReadUtil.ReadItem>();
		
		for(int i = 0; i < theadNum; i++){
			list.add(new ReadItem(file, start + i*timeReadLine*timeForTime));	//创建多个子线程
			list.get(list.size()-1).start();
		}
		
		for(int i = 0; i < list.size(); i++){
			try {
				list.get(i).join();
				sbf.append(list.get(i).getSb());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if(list.get(list.size() - 1).getLastNum() == timeReadLine){
			read(file, start + theadNum * timeReadLine * timeForTime);
		}
	}
	
	public StringBuffer getSbf() {
		return sbf;
	}

	/**
	 * 子线程
	 * @author James
	 */
	public class ReadItem extends Thread{
		private BufferedReader reader;
		private int start, lastNum;
		private StringBuffer sb;
		
		public ReadItem(File file, int start) {
			try {
				this.reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.start = start;
			this.sb = new StringBuffer();
		}

		@Override
		public void run() {
			char[] buf = new char[timeReadLine];
			try {
				reader.skip(this.start);
				for (int i = 0; i < timeForTime && (lastNum = reader.read(buf)) != -1; i++ ) {
					sb.append(new String(buf,0,lastNum));
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public int getLastNum() {
			return lastNum;
		}

		public StringBuffer getSb() {
			return sb;
		}
	}
}



  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值