多线程访问本地文件--笔记
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");
}
}
浙公网安备 33010602011771号