`
sd6292766
  • 浏览: 99990 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

JAVA多线程读写文件范例

阅读更多
    在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址。如果有知情者,烦请帖出地址,我在此文上加入引用或转载。


    本程序是基于这么一种考虑,某系统后台有个将近2G大小的日志文件,你用任何编辑器去打开它,都将会很困难。针对这样的大文件解析处理,解决方案是使用多个线程,分割读取指定的大文件。获取我们所需要的信息。不多说,上代码了,有注释可以帮助理解。


   
package com.thread.multipl.mysolution;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

/**
 * 这个线程用来读取文件,当获取到指定关键字时,在指定的对象加1
 * @author 刘峰管理2
 *
 */
public class ReadThread extends Thread{

	//定义字节数组(取水的竹筒)的长度  
    private final int BUFF_LEN = 256;  
    //定义读取的起始点  
    private long start;  
    //定义读取的结束点  
    private long end; 
    //将读取到的字节输出到raf中  randomAccessFile可以理解为文件流,即文件中提取指定的一部分的包装对象
    private RandomAccessFile raf;  
    //线程中需要指定的关键字
    private String keywords;
    //此线程读到关键字的次数
    private int curCount = 0;
    /**
     * jdk1.5开始加入的类,是个多线程辅助类
     * 用于多线程开始前统一执行操作或者多线程执行完成后调用主线程执行相应操作的类
     */
    private CountDownLatch doneSignal;
    public ReadThread(long start, long end, RandomAccessFile raf,String keywords,CountDownLatch doneSignal){
    	this.start = start;
    	this.end = end;
    	this.raf  = raf;
    	this.keywords = keywords;
    	this.doneSignal = doneSignal;
    }
    
	public void run(){
		try {
			raf.seek(start);
			//本线程负责读取文件的大小  
            long contentLen = end - start;  
            //定义最多需要读取几次就可以完成本线程的读取  
            long times = contentLen / BUFF_LEN+1;  
            System.out.println(this.toString() + " 需要读的次数:"+times);
            byte[] buff = new byte[BUFF_LEN];
            int hasRead = 0;
            String result = null;
            for (int i = 0; i < times; i++) {  
            	//之前SEEK指定了起始位置,这里读入指定字节组长度的内容,read方法返回的是下一个开始读的position
            	hasRead = raf.read(buff);
            	 //如果读取的字节数小于0,则退出循环! (到了字节数组的末尾) 
                if (hasRead < 0) {  
                    break;  
                }  
            	result = new String(buff,"gb2312");
///            	System.out.println(result);
            	int count = this.getCountByKeywords(result, keywords);
            	if(count > 0){
            		this.curCount += count;
            	}
            }
            
    		KeyWordsCount kc = KeyWordsCount.getCountObject();

    		kc.addCount(this.curCount);
    		
    		doneSignal.countDown();//current thread finished! noted by latch object!
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public long getStart() {
		return start;
	}

	public void setStart(long start) {
		this.start = start;
	}

	public long getEnd() {
		return end;
	}

	public void setEnd(long end) {
		this.end = end;
	}

	public RandomAccessFile getRaf() {
		return raf;
	}

	public void setRaf(RandomAccessFile raf) {
		this.raf = raf;
	}
	
	public int getCountByKeywords(String statement,String key){
		return statement.split(key).length-1;
	}

	public int getCurCount() {
		return curCount;
	}

	public void setCurCount(int curCount) {
		this.curCount = curCount;
	}

	public CountDownLatch getDoneSignal() {
		return doneSignal;
	}

	public void setDoneSignal(CountDownLatch doneSignal) {
		this.doneSignal = doneSignal;
	}
}


package com.thread.multipl.mysolution;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.concurrent.CountDownLatch;

public class MultiReadTest {

	/**
	 * 多线程读取文件测试
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final int DOWN_THREAD_NUM = 10;//起10个线程去读取指定文件
		final String OUT_FILE_NAME = "d:\\倚天屠龙记.txt";
		final String keywords = "无忌";
		 //jdk1.5线程辅助类,让主线程等待所有子线程执行完毕后使用的类,
        //另外一个解决方案:自己写定时器,个人建议用这个类
        CountDownLatch doneSignal = new CountDownLatch(DOWN_THREAD_NUM);
		RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM];
		try{
			long length = new File(OUT_FILE_NAME).length();
			System.out.println("文件总长度:"+length+"字节");
			//每线程应该读取的字节数  
            long numPerThred = length / DOWN_THREAD_NUM;  
            System.out.println("每个线程读取的字节数:"+numPerThred+"字节");
          //整个文件整除后剩下的余数  
            long left = length % DOWN_THREAD_NUM;
            for (int i = 0; i < DOWN_THREAD_NUM; i++) {  
                //为每个线程打开一个输入流、一个RandomAccessFile对象,  
            	
                //让每个线程分别负责读取文件的不同部分
            	outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");  
                if (i != 0) {  
//  
//                    isArr[i] = new FileInputStream("d:/勇敢的心.rmvb");  
                    //以指定输出文件创建多个RandomAccessFile对象  
                    
                }  
                if (i == DOWN_THREAD_NUM - 1) {  
//                    //最后一个线程读取指定numPerThred+left个字节  
//               	System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred+ left)+"的位置");
                    new ReadThread(i * numPerThred, (i + 1) * numPerThred  
                            + left, outArr[i],keywords,doneSignal).start();  
                } else {  
                    //每个线程负责读取一定的numPerThred个字节  
//                	System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred)+"的位置");
                    new ReadThread(i * numPerThred, (i + 1) * numPerThred,  
                            outArr[i],keywords,doneSignal).start();  
                }  
            }
		}catch(Exception e){
			e.printStackTrace();
		}
//		finally{
//			
//		}
		//确认所有线程任务完成,开始执行主线程的操作
		try {
			doneSignal.await();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//这里需要做个判断,所有做read工作线程全部执行完。
		KeyWordsCount k = KeyWordsCount.getCountObject();
//		Map<String,Integer> resultMap = k.getMap();
		System.out.println("指定关键字出现的次数:"+k.getCount());
	}

}


package com.thread.multipl.mysolution;


/**
 * 统计关键字的对象
 * @author 刘峰管理2
 *
 */

public class KeyWordsCount {
	
	private static KeyWordsCount kc;
	
	private int count = 0;
	private KeyWordsCount(){
		
	}
	
	public static synchronized KeyWordsCount getCountObject(){
		if(kc == null){
			kc = new KeyWordsCount();
		}
		return kc;
	}

	public synchronized void  addCount(int count){
		System.out.println("增加次数:"+count);
		this.count += count;
	}
	
	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}
	
}


运行结果如下:
引用
文件总长度:2012606字节
每个线程读取的字节数:201260字节
Thread[Thread-0,5,main] 需要读的次数:787
Thread[Thread-1,5,main] 需要读的次数:787
Thread[Thread-2,5,main] 需要读的次数:787
Thread[Thread-3,5,main] 需要读的次数:787
Thread[Thread-4,5,main] 需要读的次数:787
Thread[Thread-5,5,main] 需要读的次数:787
Thread[Thread-6,5,main] 需要读的次数:787
Thread[Thread-7,5,main] 需要读的次数:787
Thread[Thread-8,5,main] 需要读的次数:787
Thread[Thread-9,5,main] 需要读的次数:787
增加次数:0
增加次数:146
增加次数:432
增加次数:539
增加次数:587
增加次数:717
增加次数:631
增加次数:467
增加次数:665
增加次数:538
指定关键字出现的次数:4722


我用10个线程去解析金庸大师写的《倚天屠龙记》,“无忌”这个词在这部小说中一共出现了4722次。实在找不到再大一些的文件了。倚天屠龙记.txt的大小4M出头。

关于CountDownLatch类的作用说明:
    在API文档中,已经说明是一个辅助类。用于控制主线程与子线程之间切换的一个工具类。用法网上去搜下。ITEYE里也有人讨论过。我在这里使用它解决这样的问题:在确保10个线程都完成文件的解析工作后,系统调用主线程做剩下该做的事情,即:输出“出现的次数”。不确保这点的话,会导致执行完第4个线程,后面的线程还没开始,系统已经做最后一步输出统计结果,这样就达不到我们要的效果。这里解决方案有另一个简单的,自己写个计数器,从10记到1,10个线程嘛。这个看个人喜好吧。
分享到:
评论
2 楼 karistino 2015-11-30  
设定的进程数目不同时统计的关键字个数不一样
1 楼 zhouwei849712382 2013-03-16  
你这个我测试了,不行的

相关推荐

    JAVA 范例大全 光盘 资源

    JAVA 范例大全 光盘 资源 书籍目录: 前言. 第1章 开发环境搭建 1 实例1 下载、安装并配置JDK 1 实例2 第一个Java程序 3 实例3 在Eclipse中创建第一个Java程序 4 常见问题 javac不是内部或者外部命令 6 常见...

    java源码包---java 源码 大量 实例

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

    java范例开发大全(pdf&源码)

    实例147 随机读写Java类文件 221 第3篇 Java面向对象编程 第8章 面向对象(教学视频:72分钟) 226 8.1 类 226 实例148 简单的通讯录类 226 实例149 简单的长度单位转换类 227 实例150 卡车和卡车司机之间的关系 229...

    JAVA上百实例源码以及开源项目

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

    JAVA上百实例源码以及开源项目源代码

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术,...

    java范例开发大全

    实例147 随机读写Java类文件 221 第3篇 Java面向对象编程 第8章 面向对象(教学视频:72分钟) 226 8.1 类 226 实例148 简单的通讯录类 226 实例149 简单的长度单位转换类 227 实例150 卡车和卡车司机之间的关系 229...

    java范例开发大全源代码

     实例147 随机读写Java类文件 221  第3篇 Java面向对象编程  第8章 面向对象(教学视频:72分钟) 226  8.1 类 226  实例148 简单的通讯录类 226  实例149 简单的长度单位转换类 227  实例150 ...

    java源码包4

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术...

    java源码包3

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术...

    java源码包2

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非对称加密源程序代码实例,本例中使用RSA加密技术...

    Java范例开发大全 (源程序)

     实例147 随机读写Java类文件 221  第3篇 Java面向对象编程  第8章 面向对象(教学视频:72分钟) 226  8.1 类 226  实例148 简单的通讯录类 226  实例149 简单的长度单位转换类 227  实例150 卡车和...

    Java范例开发大全(全书源程序)

    实例147 随机读写Java类文件 221 第3篇 Java面向对象编程 第8章 面向对象(教学视频:72分钟) 226 8.1 类 226 实例148 简单的通讯录类 226 实例149 简单的长度单位转换类 227 实例150 卡车和卡车司机之间的...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密 Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密 Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义...

    Tcl_TK编程权威指南pdf

    读写操作 当前目录-cd和pwd 使用glob来匹配文件名 exit和pid命令 环境变量 registry命令 第2部分tcl高级特性 第10章 引用问题与eval 使用list命令来构建代码 在eval内部利用concat uplevel命令 subst命令...

    asp.net知识库

    读写搜索 基础教程 RSS Web2.0时代,RSS你会用了吗?(技术实现总结) 知识集锦:三分钟全面了解 Blog 和 RSS C#+ASP.NET开发基于Web的RSS阅读器 ASP.NET RSS Toolkit(RSS工具) Serialize Your Deck with Positron ...

Global site tag (gtag.js) - Google Analytics