0

1 つのフォルダに約 100 個のファイルがあります。各ファイルにはこのようなデータがあり、各行はユーザー ID に似ています。

960904056
6624084
1096552020
750160020
1776024
211592064
1044872088
166720020
1098616092
551384052
113184096
136704072

そして、その新しい大きなファイルでユーザーIDの総数が1000万になるまで、そのフォルダーから新しい大きなファイルにファイルをマージし続けようとしています。

特定のフォルダーからすべてのファイルを読み取ることができ、リンクされたハッシュセット内のそれらのファイルからユーザー ID を追加し続けます。そして、ハッシュセットのサイズが 1,000 万であるかどうかを確認し、1,000 万の場合は、それらすべてのユーザー ID を新しいテキスト ファイルに書き込むことを考えていました。それは実現可能な解決策ですか?

その 1000 万という数字は構成可能である必要があります。将来、その 1000 万 1o 50Million を変更する必要がある場合は、それができるはずです。

以下は私がこれまでに持っているコードです

public static void main(String args[]) {

    File folder = new File("C:\\userids-20130501");
    File[] listOfFiles = folder.listFiles();

    Set<String> userIdSet = new LinkedHashSet<String>();
    for (int i = 0; i < listOfFiles.length; i++) {
        File file = listOfFiles[i];
        if (file.isFile() && file.getName().endsWith(".txt")) {
            try {
                List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
                userIdSet.addAll(content);
                if(userIdSet.size() >= 10Million) {
                    break;
                }
                System.out.println(userIdSet);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

これについて何か助けていただけますか?そして、同じプロセスを行うためのより良い方法はありますか?

4

3 に答える 3

1

出発したところから続きます。;)

を使用して、メソッドFileUtilsとともにファイルを書き込むことができます。writeLines()

これを試して -

public static void main(String args[]) {

File folder = new File("C:\\userids-20130501");

Set<String> userIdSet = new LinkedHashSet<String>();
int count = 1;
for (File file : folder.listFiles()) {
    if (file.isFile() && file.getName().endsWith(".txt")) {
        try {
            List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
            userIdSet.addAll(content);
            if(userIdSet.size() >= 10Million) {
                File bigFile = new File("<path>" + count + ".txt");
                FileUtils.writeLines(bigFile, userIdSet);
                count++;
                userIdSet = new LinkedHashSet<String>(); 
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  }
}

データを保存する目的がLinkedHashSet別のファイルに再度書き込むことだけである場合は、別の解決策があります。

OutOfMemory 例外を回避するための編集

public static void main(String args[]) {
File folder = new File("C:\\userids-20130501");

int fileNameCount = 1;
int contentCounter = 1;
File bigFile = new File("<path>" + fileNameCount + ".txt");
boolean isFileRequired = true;
for (File file : folder.listFiles()) {
    if (file.isFile() && file.getName().endsWith(".txt")) {
        try {
            List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
            contentCounter += content.size();
            if(contentCounter < 10Million) {
                FileUtils.writeLines(bigFile, content, true);
            } else {
                fileNameCount++;
                bigFile = new File("<path>" + fileNameCount + ".txt");
                FileUtils.writeLines(bigFile, content);
                contentCounter = 1;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  }
}
于 2013-06-19T21:50:19.400 に答える
0

ファイルからの読み取りと同時に書き込みを行うと、Set を中間ストレージとして使用することを避けることができます。あなたはこのようなことをすることができます、

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;


public class AppMain {
  private static final int NUMBER_REGISTERS = 10000000;

  private static String[] filePaths = {"filePath1", "filePaht2", "filePathN"}; 
  private static String mergedFile = "mergedFile";


  public static void main(String[] args) throws IOException {
    mergeFiles(filePaths, mergedFile);
  }

  private static void mergeFiles(String[] filePaths, String mergedFile) throws IOException{
    BufferedReader[] readerArray = createReaderArray(filePaths);
    boolean[] closedReaderFlag = new boolean[readerArray.length];

    PrintWriter writer = createWriter(mergedFile);

    int currentReaderIndex = 0;
    int numberLinesInMergedFile = 0;

    BufferedReader currentReader = null;
    String currentLine = null;
    while(numberLinesInMergedFile < NUMBER_REGISTERS && getNumberReaderClosed(closedReaderFlag) < readerArray.length){
      currentReaderIndex = (currentReaderIndex + 1) % readerArray.length; 

      if(closedReaderFlag[currentReaderIndex]){
       continue;
      }

      currentReader = readerArray[currentReaderIndex];

      currentLine = currentReader.readLine();
      if(currentLine == null){
       currentReader.close();
       closedReaderFlag[currentReaderIndex] = true;
       continue;
      }

      writer.println(currentLine);
      numberLinesInMergedFile++;
    }

    writer.close();
    for(int index = 0; index < readerArray.length; index++){
      if(!closedReaderFlag[index]){
       readerArray[index].close();
      }
    }

  }

  private static BufferedReader[] createReaderArray(String[] filePaths) throws FileNotFoundException{
    BufferedReader[] readerArray = new BufferedReader[filePaths.length];

    for (int index = 0; index < readerArray.length; index++) {
      readerArray[index] = createReader(filePaths[index]);
    }

    return readerArray;
  }

  private static BufferedReader createReader(String path) throws FileNotFoundException{
    BufferedReader reader = new BufferedReader(new FileReader(path));

    return reader;
  }

  private static PrintWriter createWriter(String path) throws FileNotFoundException{
    PrintWriter writer = new PrintWriter(path);

    return writer;
  }

  private static int getNumberReaderClosed(boolean[] closedReaderFlag){
    int count = 0;

    for (boolean currentFlag : closedReaderFlag) {
      if(currentFlag){
    count++;
      }
    }

    return count;
  }
}
于 2013-06-19T21:27:14.523 に答える
0

あなたが行っている方法では、メモリが不足する可能性があり、不要なレコードをuserIdSetに保持しています。

コードを改善できるわずかな変更は次のとおりです。

public static void main(String args[]) {

    File folder = new File("C:\\userids-20130501");
    File[] listOfFiles = folder.listFiles();

    // there's no need for the userIdSet!
    //Set<String> userIdSet = new LinkedHashSet<String>();

    // Instead I'd go for a counter ;)
    long userIdCount = 0;

    for (int i = 0; i < listOfFiles.length; i++) {
        File file = listOfFiles[i];
        if (file.isFile() && file.getName().endsWith(".txt")) {
            try {
                List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));
                // I just want to know how many lines there are...
                userIdCount += content.size();

                // my guess is you'd probably want to print what you've got
                // before a possible break?? - You know better!
                System.out.println(content);

                if(userIdCount >= 10Million) {
                    break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

おっしゃる通り、ちょっとした改造です。あなたのコードを非常に詳細に分析するつもりはありませんでした。明らかな設計ミスを指摘しただけです。

最後に、System.out.println(content);と述べた場所 、その時点でファイルへの書き込みを検討するかもしれません。

一度に 1 行ずつファイルに書き込む場合、try-catch ブロックは次のようになります。

try {
    List<String> content = FileUtils.readLines(file, Charset.forName("UTF-8"));

    for(int lineNumber = 0; lineNumber < content.size(); lineNumber++){
        if(++userIdCount >= 10Million){
           break;
        }
        // here, write to file... But I will use simple System.out.print for example
        System.out.println(content.get(lineNumber));
    }
} catch (IOException e) {
    e.printStackTrace();
}

コードはさまざまな方法で改善できますが、それを行う時間がありません。しかし、私の提案があなたを正しい道でさらに前に押し出すことができることを願っています. 乾杯!

于 2013-06-19T21:44:29.047 に答える