这篇文章写得不错:https://www.cnblogs.com/metoy/p/4470418.html?utm_source=tuicool&utm_medium=referral
1.背景:目前有一个约有一个300MB的文本文件,需要将里面的数据提取出来存到数据库。
2.解决思路:我是将这个300MB的文件切割成31个相同大小的文件 ,然后使用10个线程解析这31个文件,每个线程处理三个文件,使用 synchronized 关键字对文件资源加锁,防止一个文件被俩个线程读到。大约测试一下时间在6-7秒。
synchronized关键字:能够保证同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果
可以看下这篇文章:https://www.cnblogs.com/YpfBolg/p/10805496.html
3.话不多说,上代码! 如果写的不错的话,大家点个赞鼓励一下, 如有写的不完善的地方,欢迎大家在评论区指出,共同进步!
/***
* 解析文件内容
*/
@Test
public void parseFileContent() {
Long startTime = System.currentTimeMillis();
Map<String, File> map = new HashMap<String, File>();
//将这个路径形成一个唯一标识(加上文件名称) 可以区分存储的文件
String uploadPath = "D:/testFile/test.txt";
FileUtil fileUtil = new FileUtil();
fileUtil.parseFile(uploadPath);
//接下来遍历整个文件夹里的31个分割后的文件
File[] files = new File("D:/testFile").listFiles();
String fileName = "";
for (File fileInfo : files) {
if (fileInfo.isFile() && fileInfo.exists() && fileInfo.getName().contains("part")) {
fileName = fileInfo.getName();
map.put(fileName, fileInfo);
}
}
//创建自定义线程对象(开启10个线程来解析这三十一个文件)
FileThreadResource resource = new FileThreadResource();
for (int k = 0; k < 10; k++) {
ParseFileThread mt = new ParseFileThread(map, resource);
mt.run();
}
Long endTime = System.currentTimeMillis();
System.out.println("总共花了--"+(endTime -startTime)/1000+"---秒");
}
4.接下来我将代码中涉及的一些类贴上来!
A.FileUtil中的类
public void parseFile(String fileUrl) {
try {
long timer = System.currentTimeMillis();
//设读取文件的缓存为20MB
int bufferSize = 20 * 1024 * 1024;
//建立缓冲文本输入流
File file = new File(fileUrl);
FileInputStream fileInputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
//注意这里有时会乱码,根据自己的文本存储格式,进行调整
InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream, "utf-8");
BufferedReader input = new BufferedReader(inputStreamReader, bufferSize);
long fileSize = getLineNumber(file);
//要分割的块数减一,这里表示分割为31个文件
int splitNum = 30;
//fileLines表示我的输入本文的行数,由于每行文本较长,所有存储占用较大
int fileLines = (int) fileSize;
//分割后存储每个块的行数
long perSplitLines = fileLines / splitNum;
for (int i = 0; i <= splitNum; ++i) {
//分割
//每个块建立一个输出
BufferedWriter output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("D:/testFile/" + "part" + i + ".txt")), "utf-8"));
String line = null;
//逐行读取,逐行输出
for (long lineCounter = 0; lineCounter < perSplitLines && (line = input.readLine()) != null; ++lineCounter) {
output.append(line + "\r");
}
output.flush();
output.close();
output = null;
}
input.close();
timer = System.currentTimeMillis() - timer;
logger.info("分割文件处理时间:" + timer);
} catch (Exception e) {
logger.error("分割文件异常---", e);
}
}
/**
* 获取整个文件有多少行
* @param file
* @return
*/
public long getLineNumber(File file) {
if (file.exists()) {
try {
FileReader fileReader = new FileReader(file);
LineNumberReader lineNumberReader = new LineNumberReader(fileReader);
lineNumberReader.skip(Long.MAX_VALUE);
long lines = lineNumberReader.getLineNumber() + 1;
fileReader.close();
lineNumberReader.close();
return lines;
} catch (IOException e) {
e.printStackTrace();
}
}
return 0;
}
/**
用来解析文件的线程
* @Author: tanghh18
* @Date: 2019/8/5 18:54
*/
public class ParseFileThread extends FileThreadResource implements Runnable {
private Map<String, File> map;
private FileThreadResource resource;
public ParseFileThread(Map<String, File> map, FileThreadResource resource) {
this.map = map;
this.resource = resource;
}
@Override
public void run() {
synchronized (resource) {
int i = resource.getFileIndex();
for (int j = 1; j <= 3; j++) {
File file = map.get("part" + i + ".txt");
try {
List<String> logInfoList = importFile(file, "utf-8");
System.out.println("总共多少条数据---"+logInfoList.size());
i++;
resource.setFileIndex(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 8.读取.txt文件中的数据,存入集合中
*/
public List<String> importFile(File file, String encoding) throws IOException, ParseException {
List<String> allLineList = new ArrayList<>();
InputStreamReader reader = null;
String line = "";
try {
reader = new InputStreamReader(new FileInputStream(file), encoding);
BufferedReader bufferedReader = new BufferedReader(reader);
while ((line = bufferedReader.readLine()) != null) {
allLineList.add(line);
}
} catch (Exception e) {
}
return allLineList;
}
}
/**
* 功能描述: 所有线程共享这个资源类
* @Author: tanghh18
* @Date: 2019/7/24 9:51
*/
public class FileThreadResource {
/**
* 定义一个初始化变量
*/
private Integer fileIndex=0;
public Integer getFileIndex() {
return fileIndex;
}
public void setFileIndex(Integer fileIndex) {
this.fileIndex = fileIndex;
}
}
5,最后看一下效果。首先是分割后的文件。
6.其次是程序执行效果。