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

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

  1. package com.thread.multipl.mysolution;
  2. import java.io.IOException;
  3. import java.io.RandomAccessFile;
  4. import java.util.concurrent.CountDownLatch;
  5. /**
  6. * 这个线程用来读取文件,当获取到指定关键字时,在指定的对象加1
  7. * @author 刘峰管理2
  8. *
  9. */
  10. public class ReadThread extends Thread{
  11. //定义字节数组(取水的竹筒)的长度
  12. private final int BUFF_LEN = 256;
  13. //定义读取的起始点
  14. private long start;
  15. //定义读取的结束点
  16. private long end;
  17. //将读取到的字节输出到raf中  randomAccessFile可以理解为文件流,即文件中提取指定的一部分的包装对象
  18. private RandomAccessFile raf;
  19. //线程中需要指定的关键字
  20. private String keywords;
  21. //此线程读到关键字的次数
  22. private int curCount = 0;
  23. /**
  24. * jdk1.5开始加入的类,是个多线程辅助类
  25. * 用于多线程开始前统一执行操作或者多线程执行完成后调用主线程执行相应操作的类
  26. */
  27. private CountDownLatch doneSignal;
  28. public ReadThread(long start, long end, RandomAccessFile raf,String keywords,CountDownLatch doneSignal){
  29. this.start = start;
  30. this.end = end;
  31. this.raf  = raf;
  32. this.keywords = keywords;
  33. this.doneSignal = doneSignal;
  34. }
  35. public void run(){
  36. try {
  37. raf.seek(start);
  38. //本线程负责读取文件的大小
  39. long contentLen = end - start;
  40. //定义最多需要读取几次就可以完成本线程的读取
  41. long times = contentLen / BUFF_LEN+1;
  42. System.out.println(this.toString() + " 需要读的次数:"+times);
  43. byte[] buff = new byte[BUFF_LEN];
  44. int hasRead = 0;
  45. String result = null;
  46. for (int i = 0; i < times; i++) {
  47. //之前SEEK指定了起始位置,这里读入指定字节组长度的内容,read方法返回的是下一个开始读的position
  48. hasRead = raf.read(buff);
  49. //如果读取的字节数小于0,则退出循环! (到了字节数组的末尾)
  50. if (hasRead < 0) {
  51. break;
  52. }
  53. result = new String(buff,"gb2312");
  54. ///             System.out.println(result);
  55. int count = this.getCountByKeywords(result, keywords);
  56. if(count > 0){
  57. this.curCount += count;
  58. }
  59. }
  60. KeyWordsCount kc = KeyWordsCount.getCountObject();
  61. kc.addCount(this.curCount);
  62. doneSignal.countDown();//current thread finished! noted by latch object!
  63. } catch (IOException e) {
  64. // TODO Auto-generated catch block
  65. e.printStackTrace();
  66. }
  67. }
  68. public long getStart() {
  69. return start;
  70. }
  71. public void setStart(long start) {
  72. this.start = start;
  73. }
  74. public long getEnd() {
  75. return end;
  76. }
  77. public void setEnd(long end) {
  78. this.end = end;
  79. }
  80. public RandomAccessFile getRaf() {
  81. return raf;
  82. }
  83. public void setRaf(RandomAccessFile raf) {
  84. this.raf = raf;
  85. }
  86. public int getCountByKeywords(String statement,String key){
  87. return statement.split(key).length-1;
  88. }
  89. public int getCurCount() {
  90. return curCount;
  91. }
  92. public void setCurCount(int curCount) {
  93. this.curCount = curCount;
  94. }
  95. public CountDownLatch getDoneSignal() {
  96. return doneSignal;
  97. }
  98. public void setDoneSignal(CountDownLatch doneSignal) {
  99. this.doneSignal = doneSignal;
  100. }
  101. }
  1. package com.thread.multipl.mysolution;
  2. import java.io.File;
  3. import java.io.RandomAccessFile;
  4. import java.util.concurrent.CountDownLatch;
  5. public class MultiReadTest {
  6. /**
  7. * 多线程读取文件测试
  8. * @param args
  9. */
  10. public static void main(String[] args) {
  11. // TODO Auto-generated method stub
  12. final int DOWN_THREAD_NUM = 10;//起10个线程去读取指定文件
  13. final String OUT_FILE_NAME = "d:\\倚天屠龙记.txt";
  14. final String keywords = "无忌";
  15. //jdk1.5线程辅助类,让主线程等待所有子线程执行完毕后使用的类,
  16. //另外一个解决方案:自己写定时器,个人建议用这个类
  17. CountDownLatch doneSignal = new CountDownLatch(DOWN_THREAD_NUM);
  18. RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM];
  19. try{
  20. long length = new File(OUT_FILE_NAME).length();
  21. System.out.println("文件总长度:"+length+"字节");
  22. //每线程应该读取的字节数
  23. long numPerThred = length / DOWN_THREAD_NUM;
  24. System.out.println("每个线程读取的字节数:"+numPerThred+"字节");
  25. //整个文件整除后剩下的余数
  26. long left = length % DOWN_THREAD_NUM;
  27. for (int i = 0; i < DOWN_THREAD_NUM; i++) {
  28. //为每个线程打开一个输入流、一个RandomAccessFile对象,
  29. //让每个线程分别负责读取文件的不同部分
  30. outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");
  31. if (i != 0) {
  32. //
  33. //                    isArr[i] = new FileInputStream("d:/勇敢的心.rmvb");
  34. //以指定输出文件创建多个RandomAccessFile对象
  35. }
  36. if (i == DOWN_THREAD_NUM - 1) {
  37. //                    //最后一个线程读取指定numPerThred+left个字节
  38. //                  System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred+ left)+"的位置");
  39. new ReadThread(i * numPerThred, (i + 1) * numPerThred
  40. + left, outArr[i],keywords,doneSignal).start();
  41. } else {
  42. //每个线程负责读取一定的numPerThred个字节
  43. //                  System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred)+"的位置");
  44. new ReadThread(i * numPerThred, (i + 1) * numPerThred,
  45. outArr[i],keywords,doneSignal).start();
  46. }
  47. }
  48. }catch(Exception e){
  49. e.printStackTrace();
  50. }
  51. //      finally{
  52. //
  53. //      }
  54. //确认所有线程任务完成,开始执行主线程的操作
  55. try {
  56. doneSignal.await();
  57. } catch (InterruptedException e) {
  58. // TODO Auto-generated catch block
  59. e.printStackTrace();
  60. }
  61. //这里需要做个判断,所有做read工作线程全部执行完。
  62. KeyWordsCount k = KeyWordsCount.getCountObject();
  63. //      Map<String,Integer> resultMap = k.getMap();
  64. System.out.println("指定关键字出现的次数:"+k.getCount());
  65. }
  66. }
  1. package com.thread.multipl.mysolution;
  2. /**
  3. * 统计关键字的对象
  4. * @author 刘峰管理2
  5. *
  6. */
  7. public class KeyWordsCount {
  8. private static KeyWordsCount kc;
  9. private int count = 0;
  10. private KeyWordsCount(){
  11. }
  12. public static synchronized KeyWordsCount getCountObject(){
  13. if(kc == null){
  14. kc = new KeyWordsCount();
  15. }
  16. return kc;
  17. }
  18. public synchronized void  addCount(int count){
  19. System.out.println("增加次数:"+count);
  20. this.count += count;
  21. }
  22. public int getCount() {
  23. return count;
  24. }
  25. public void setCount(int count) {
  26. this.count = count;
  27. }
  28. }

运行结果如下:

引用
文件总长度: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个线程嘛。这个看个人喜好吧。

原文:http://babystudyjava.iteye.com/blog/1732814

JAVA多线程读写文件范例的更多相关文章

  1. java StringBuffer读写文件

    java StringBuffer读写文件 StringBuffer的优势 较String:String每更新一次就会new一个新的对象出来,更新次数上去之后,内存开销太大.而StringBuffer ...

  2. java io读写文件

    java io读写文件相关阅读:http://www.cnblogs.com/wing011203/archive/2013/05/03/3056535.html public class DemoI ...

  3. java(IO)读写文件乱码转换UTF-8问题

    java(IO)读写文件乱码转换UTF-8问题 读取文件 String Content = ""; // 文件很长的话建议使用StringBuffer try { FileInpu ...

  4. SAE java应用读写文件(TmpFS和Storage)-----绝世好代码

    近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...

  5. SAE java应用读写文件(TmpFS和Storage)

    近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...

  6. java 多线程下载文件 以及URLConnection和HttpURLConnection的区别

    使用 HttpURLConnection 实现多线程下载文件 注意GET大写//http public class MultiThreadDownload { public static void m ...

  7. Java基础--读写文件

    Java读写文件需要注意异常的处理,下面是一个例子 写文件 public class WriteFile { public static void write(String file, String ...

  8. 顺序、随机IO和Java多种读写文件性能对比

    概述 对于磁盘的读写分为两种模式,顺序IO和随机IO. 随机IO存在一个寻址的过程,所以效率比较低.而顺序IO,相当于有一个物理索引,在读取的时候不需要寻找地址,效率很高. 基本流程 总体结构 我们编 ...

  9. java 多线程下载文件并实时计算下载百分比(断点续传)

    多线程下载文件 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来 ...

随机推荐

  1. angular项目中使用ngSemantic

    npm install ng-semantic --save npm install jquery --save 下载 Official Semantic UI bundle ( .zip ) fro ...

  2. 重置HTML标签样式

    ;;} header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:bl ...

  3. LightOJ 1369 Answering Queries(找规律)

    题目链接:https://vjudge.net/contest/28079#problem/P 题目大意:给你数组A[]以及如下所示的函数f: long long f( int A[], int n  ...

  4. prototype 与 __proto__

    原文:http://rockyuse.iteye.com/blog/1426510 说到prototype,就不得不先说下new的过程. 我们先看看这样一段代码: 1 <script type= ...

  5. CSU 1425 Prime Summation

    原题链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1425 DP题. f[i][j]表示当前数字为i,分解式中最大质数为j的方案数,那么,状态 ...

  6. 在Windows中安装Boot2Docker 遇到 Unable to load R3 module 的解决方案

    引言 这个几乎是所有64位win7用户在virtual box上安装64位的linux都会遇到的问题(如果你用的是买机器的时候自带的win7 64位而且你没有重装过系统的除外). 解决办法 可参考以下 ...

  7. [你必须知道的.NET]第十九回:对象创建始末(下)

    本文将介绍以下内容: 对象的创建过程 内存分配分析 内存布局研究 接上回[第十八回:对象创建始末(上)],继续对对象创建话题的讨论>>> 2.2 托管堆的内存分配机制 引用类型的实例 ...

  8. go接口及嵌入类型例子

    书上看的.慢慢领会.. package main import ( "fmt" ) type notifier interface { notify() } type user s ...

  9. fastdfs5.11+centos7.2 按照部署(三)【转载】

    1.测试 前面两篇博文已对FastDFS的安装和配置,做了比较详细的讲解.FastDFS的基础模块都搭好了,现在开始测试下载. 1.1 配置客户端 同样的,需要修改客户端的配置文件: vim /etc ...

  10. scala windows 安装

    下载 https://downloads.lightbend.com/scala/2.11.11/scala-2.11.11.msi 第一步:设置 右击我的电脑,单击"属性",进入 ...