Разбить огромный файл целых чисел (в одну строку) на отсортированные куски с ограничением памяти - PullRequest
7 голосов
/ 27 сентября 2019

Мне недавно нужно было отсортировать однострочный файл (целые числа, разделенные ",") на более мелкие куски с учетом ограничений памяти и эффективности.В настоящее время я придерживаюсь этой логики:

File file = new File("bigfile.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int BUFFER_SIZE = 10; // can and should be bigger
byte[] bytes = new byte[BUFFER_SIZE];
while ((bis.read(bytes)) != -1) {
   // convert bytes to string
   // split bytes to String[]
   // save the last number if was cut in the middle and save it for the next round of reading and remove it from the current String[]
   // fix cut number if necessary and put it in the String[]
   // sort the String[]
   // write the String[] into a file
   // call Garbage collector to prevent memory leak?
}
bis.close();

Предполагая, что я ограничен 5 МБ памяти и мне нужно прочитать однострочный файл с 10 000 000 целых чисел, разделенных ",":

  • Если я использую очень маленький размер буфера (например, 10) для чтения файла, я создам тысячи файлов.
  • Если я использую приличный, но все еще небольшой буферразмер (например, 100 КБ), тогда я все равно получу много файлов.
  • Если я буду использовать больший размер буфера (например, 4 МБ), то у меня возникнут проблемы с кучей при сортировке и разбиении результата в памяти из-заограничение.

Каков наилучший подход для меня, чтобы получить наименьшее количество отсортированных файлов (или наибольшие порции данных на файл)?

1 Ответ

1 голос
/ 27 сентября 2019

Задача не из легких.Я уверен, что это не лучший подход, но лучше, чем ничего:

  1. Найти или создать list как PriorityQueue с size и comparator аргументами конструктора.Размер должен быть известен (согласно вашему требованию)
    • Метод add(..) должен соответствовать O(log n) и сортировать элементы при вставке их
    • Метод add(..) должен возвращать false, когда список полностью заполнен(в противном случае true)
  2. Выполните чтение потока и немедленно (без буферизации) добавьте целые числа в свою коллекцию.Создайте новый список, если свободного места нет.
  3. Теперь у вас есть коллекция отсортированных списков.Последний шаг - сортировка данных по спискам: [1,4,5],[3,8,9],[2,6,7] -> [1,2,3], [4,5,6], [7,8,9] Например, путем выбора минимумов из списка № 1 и № 2, их сравнения и так далее.,.

ПРИМЕЧАНИЕ: Также вы можете выполнить Шаг № 3 одновременно

О # 2: Я пропустил, что у вас есть строковые данные.Так что разбор последовательности байтов в целые числа - плохая идея.Однако должна быть возможность анализировать данные char-by-char и затем преобразовывать их в int при появлении запятой.Кроме того, размер буфера может быть рассчитан (максимальная длина числа * байтов на символ) -> для 2147483647, в UTF-8 это 11 * 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...