1

我正在尝试开发一个多线程 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);

    }

}

我想编写这个程序的多线程版本,但我不知道如何读取从指定行开始的文件。请帮帮我。:(

4

2 回答 2

2

我想编写这个程序的多线程版本,但我不知道如何读取从指定行开始的文件。请帮帮我。:(

正如这暗示的那样,我不会让每个线程从文件开头读取忽略行,直到它们到达输入文件的部分。这是非常低效的。正如您所暗示的那样,如果要按行将文件分成块,则读者必须阅读所有先前的行。这意味着一大堆重复的读取 IO,这将导致应用程序变慢。

相反,您可以有 1 个读者和 N 个作者。读者将添加要写入某种类型的BlockingQueue每个作者的行。这样做的问题是您可能不会获得任何并发性。一次很可能只有一名编写者在工作,而其余编写者则等待读者到达他们输入文件的一部分。此外,如果读取器比写入器快(这很可能),那么如果要分割的文件很大,那么您很容易耗尽内存来排队内存中的所有行。您可以使用大小有限的阻塞队列,这意味着读取器可能会阻塞等待写入器,但同样,多个写入器很可能不会同时运行。

正如评论中提到的,由于这些限制,最有效的方法是单线程。如果您将此作为练习进行,那么听起来您需要一次阅读文件,记下每个输出文件在文件中的开始和结束位置,然后使用这些位置分叉线程,以便它们可以重新-读取文件并将其并行写入单独的输出文件,而无需大量行缓冲。

于 2013-07-29T15:53:45.637 回答
0

您只需要读取一次文件,并将其存储到 List 中:

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

有关线程池的更多信息,请阅读

于 2013-07-29T15:16:15.693 回答