多线程访问本地文件--笔记

package testthree;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.security.InvalidParameterException;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadReadFile {
  private static AtomicInteger atomicInteger = new AtomicInteger(0);


  public static void main(String[] args) throws Exception {
    long beginTime = System.currentTimeMillis();
    System.out.println("--beginTime--"+beginTime);
    ThreadReadFile helper = new ThreadReadFile();
    helper.read("C:\\Users\\xingyang\\Desktop\\test.txt", Runtime.getRuntime().availableProcessors(), '\n',
    new StringCallback("UTF-8") {
      @Override
      public void callback(String data) {//new抽象类,先要重写它的所有抽象方法
        int count = atomicInteger.incrementAndGet();
        if (count == 1000000) {
          System.out.println("总耗时毫秒:" + (System.currentTimeMillis() - beginTime));
          System.out.println(data);
        }
      }
    });
  }
  public void read(String path, int threadCount, char separator, StringCallback callback) throws IOException {
    System.out.println("--begin---read"+"separator:"+separator);
    if (threadCount < 1)
      throw new InvalidParameterException("The threadCount can not be less than 1");
    if (path == null || path.isEmpty())
      throw new InvalidParameterException("The path can not be null or empty");
    if (callback == null)
      throw new InvalidParameterException("The callback can not be null");
    RandomAccessFile randomAccessFile = new RandomAccessFile(path, "r"); //检查是否有权限操作文件,是否存在 。"r"表示只读模式。“rw"表示读写模式
    long fileTotalLength = randomAccessFile.length();//文件中的字符个数 198959212
    long gap = fileTotalLength / threadCount; //每个线程要处理多少个字符的整数 99479606,相处商取整数
    long checkIndex = 0;
    long[] beginIndexs = new long[threadCount];
    long[] endIndexs = new long[threadCount];
    //以换行符进行分割成坐标
    for (int n = 0; n < threadCount; n++) {
      beginIndexs[n] = checkIndex;//beginIndex[0]=0
      if (n + 1 == threadCount) {
        endIndexs[n] = fileTotalLength; //第二个坐标值:全部长度
        break;
      }
      checkIndex += gap;//checkIndex= 商取整数+2个字节,
      long gapToEof = getGapToEof(checkIndex, randomAccessFile, separator); //
      checkIndex += gapToEof;
      endIndexs[n] = checkIndex; //第一个坐标值:一半+下一个换行之前的数量
    }


    ExecutorService executorService = Executors.newFixedThreadPool(threadCount);//创建线程
    System.out.println("----创建线程对象结束----");
    executorService.execute(() -> {
      try {
        readData(beginIndexs[0], endIndexs[0], path, randomAccessFile, separator, callback);
      } catch (Exception e) {
        e.printStackTrace();
      }
    });
    for (int n = 1; n < threadCount; n++) {
      long begin = beginIndexs[n];
      long end = endIndexs[n];
      executorService.execute(() -> {
        try {
          readData(begin, end, path, null, separator, callback);
        } catch (Exception e) {
          e.printStackTrace();
        }
      });
    }
  }
  /*
  * @Param beginIndex表示读取最后的下标
  * @Param randomAccessFile文件信息
  * @Param separator表示换行
  */
  private long getGapToEof(long beginIndex, RandomAccessFile randomAccessFile, char separator) throws IOException {
    randomAccessFile.seek(beginIndex);//移动指针到任意位置,beginIndex+2个字节后开始
    long count = 0;
    while (randomAccessFile.read()/*读取2个字节*/ != separator) {//读取文件知道换行,计算数量10000个换行符
      count++;
    }
    count++;//到下一个换行符之前有多少字节*2
    return count;
  }


  private void readData(long begin, long end, String path, RandomAccessFile randomAccessFile,
    char separator, StringCallback callback) throws FileNotFoundException, IOException {
    System.out.println("开始工作:" + Thread.currentThread().getName());
    if (randomAccessFile == null) {
      randomAccessFile = new RandomAccessFile(path, "r");
    }
    randomAccessFile.seek(begin); //移动坐标
    StringBuilder builder = new StringBuilder();
    while (true) {
      int read = randomAccessFile.read();
      begin++;
      if (separator == read) {
        if (callback != null) {//换行了,判断是否到最后了
          callback.callback0(builder.toString());
        }
        builder = new StringBuilder();
      } else {
        builder.append((char) read);
      }
      if (begin >= end) { //从计数开始,结束就跳出循环
        break;
      }
    }
    randomAccessFile.close();
  }

  /**

  **/
  public static abstract class StringCallback {
    private String charsetName;
    private ExecutorService executorService = Executors.newSingleThreadExecutor();
    public StringCallback(String charsetName) {
      this.charsetName = charsetName;
    }
    private void callback0(String data) {
      executorService.execute(() -> {
        try {
          callback(new String(data.getBytes("ISO-8859-1"), charsetName));
        } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
        }
      });
    }
    abstract void callback(String data);
  }
  // 模拟数据
  private static void writeData() throws FileNotFoundException, IOException {
    FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\test\\Desktop\\test.txt");
    Random random = new Random();
    for (int n = 0; n < 1000000; n++) {
      int count = random.nextInt(10) + 1;
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < count; i++) {
        builder.append(UUID.randomUUID().toString());
      }
      builder.append("\n");
      fileOutputStream.write(builder.toString().getBytes());
    }
    fileOutputStream.close();
    System.out.println("ok");
  }
}

posted @ 2018-03-06 17:12  Snowlanhua  阅读(184)  评论(0)    收藏  举报