Объединяйте файлы в новый большой файл, пока число идентификаторов пользователей не станет 10 миллионов

У меня есть около 100 файлов в папке. Каждый файл будет иметь такие данные, и каждая строка будет напоминать идентификатор пользователя.

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

И я пытаюсь продолжать объединять файлы из этой папки в новый большой файл, пока общее число идентификаторов пользователей не станет 10 миллионами в этом новом большом файле.

Я могу прочитать все файлы из определенной папки, а затем продолжаю добавлять идентификаторы пользователей из этих файлов в связанный хэш-сет. А потом я подумал, посмотреть, равен ли размер хэш-набора 10 миллионам, а если он равен 10 миллионам, запишите все эти идентификаторы пользователей в новый текстовый файл. Это возможное решение?

Это число 10 миллионов должно быть настраиваемым. В будущем, если мне нужно изменить эти 10 миллионов на 50 миллионов, я смогу это сделать.

Ниже приведен код, который я до сих пор

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();
            }
        }
    }
}

Любая помощь будет оценена по этому вопросу? И есть ли лучший способ сделать тот же процесс?

3 ответа

Решение

Продолжая от того, где мы уехали.;)

Вы можете использовать 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();
        }
    }
  }
}

То, как вы идете, скорее всего, вам не хватает памяти, вы храните ненужную запись в 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);, вы можете рассмотреть возможность записи в файл в этот момент.

Если вы будете писать в файл по одной строке за раз, блок 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();
}

Ваш код может быть улучшен многими способами, но у меня нет времени, чтобы сделать это. Но я надеюсь, что мое предложение может подтолкнуть вас вперед на правильном пути. Ура!

Вы можете избежать использования набора в качестве промежуточного хранилища, если вы пишете одновременно с чтением из файла. Вы могли бы сделать что-то вроде этого,

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;
  }
}
Другие вопросы по тегам