我正在尝试开发一个多线程java程序,用于将大型文本文件拆分为较小的文本文件。创建的较小文件必须具有前缀数量的行。 例如: 如果输入文件的行数是100而输入的数字是10,我的程序的结果是将输入文件分成10个文件。 我已经开发了我的程序的单线程版本:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TextFileSingleThreaded {
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Invalid Input!");
}
//first argument is the file path
File file = new File(args[0]);
//second argument is the number of lines per chunk
//In particular the smaller files will have numLinesPerChunk lines
int numLinesPerChunk = Integer.parseInt(args[1]);
BufferedReader reader = null;
PrintWriter writer = null;
try {
reader = new BufferedReader(new FileReader(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String line;
long start = System.currentTimeMillis();
try {
line = reader.readLine();
for (int i = 1; line != null; i++) {
writer = new PrintWriter(new FileWriter(args[0] + "_part" + i + ".txt"));
for (int j = 0; j < numLinesPerChunk && line != null; j++) {
writer.println(line);
line = reader.readLine();
}
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
writer.close();
long end = System.currentTimeMillis();
System.out.println("Taken time[sec]:");
System.out.println((end - start) / 1000);
}
}
我想编写这个程序的多线程版本,但我不知道如何从指定的行开始读取文件。请帮帮我。 :(
答案 0 :(得分:2)
我想编写这个程序的多线程版本,但我不知道如何从指定的行开始读取文件。请帮帮我。 :(
我不会,因为这暗示,每个线程从文件的开头读取,忽略行,直到它们到达输入文件的部分。这是非常低效的。正如您所暗示的那样,如果文件将按行划分为块,则读者必须阅读所有先前的行。这意味着一大堆重复的读取IO将导致应用程序变慢。
你可以改为拥有1位读者和N位作家。读者将添加要写入每个作者某种BlockingQueue
的行。这个问题是你很可能不会得到任何并发性。只有一个作者最有可能同时工作,而其余的作者等待读者到达他们输入文件的一部分。此外,如果阅读器比编写器更快(很可能),那么如果要分割的文件很大,则可能很容易耗尽内存中的所有行。你可以使用一个大小有限的阻塞队列,这意味着读者可能会阻止等待编写者,但同样,多个编写者很可能不会同时运行。
正如评论中所提到的,由于这些限制,最有效的方法是单线程。如果您将此作为练习,那么听起来您需要一次读取文件,记下文件中每个输出文件的开始和结束位置,然后将线程分叉到这些位置以便它们可以重新开始 - 读取文件并将其并行写入单独的输出文件,而无需大量的行缓冲。
答案 1 :(得分:0)
您只需要读取一次文件,并将其存储到列表中:
BufferedReader br = new BufferedReader(new FileReader(new File("yourfile")));
List<String> list = new ArrayList<String>();
String line;
//for each line of your file
while((line = br.readLine()) != null){
list.add(line);
}
br.close();
//then you can split your list into differents parts
List<List<String>> parts = new ArrayList<ArrayList<String>>();
for(int i = 0; i < 10; i++){
parts.add(new ArrayList<String>());
for(int j =0; j < 10; j++){
parts.get(i).add(list.get(i*10+j));
}
}
//now you have 10 lists which each contain 10 lines
//you still need to to create a thread pool, where each thread put a list into a file
有关线程池的更多信息,请阅读this。