【问题标题】:how to split a large text file into smaller chunks using java multithread如何使用java多线程将大文本文件拆分成更小的块
【发布时间】:2013-07-29 14:59:58
【问题描述】:

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

    }

}

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

【问题讨论】:

  • 如果有任何问题,我怀疑您的应用程序的多线程版本是否会运行得更快,因为您很可能受 IO 限制。如果您运行您的程序并且它使用的处理器显着少于 100%,那么添加更多线程很可能只会给您带来适度的速度提升(如果有的话)。仅供参考。
  • 你为什么要这样做?如果是为了性能,你应该知道一个线程更简单,通常也更快。要确定一行的开始位置,您需要阅读上一行,这意味着它基本上是一个单线程进程。
  • @Gray,我想如果程序从一个 HDD 读取并写入另一个 HDD,那么实际上具有生产者/消费者模式会加快速度。如果进程正在读取和写入同一个 HDD,那么单个线程几乎肯定会更快,因为多个线程会导致硬盘抖动。
  • 没错,我必须证明在这种情况下多线程会导致垃圾。
  • 但首先我必须编写一个使用多线程的程序进行实验,并且我还需要了解这种方法的优缺点。如果我有更多 HDD 或分布式文件系统多线程工作良好

标签: java multithreading file-io split


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    您只需要读取一次文件,并将其存储到 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
    

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

    【讨论】:

    • 始终使用interface 而不是实现。所以List&lt;List&lt;String&gt;&gt; parts = new ArrayList&lt;List&lt;String&gt;&gt;()。正如上面多次提到的,这可能弊大于利。
    • 如果我的文件很大?这种方法效率不高
    • @BoristheSpider 已修复 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 2013-04-05
    相关资源
    最近更新 更多