Читайте десятки тысяч файлов и пишите в миллионы файлов в Java

59
6

Я делаю некоторые необычные манипуляции с данными. У меня 36 000 входных файлов. Более того можно сразу загрузить в память. Я хочу взять первый байт каждого файла и поместить его в один выходной файл, а затем сделать это снова для второго и так далее. Это не нужно делать в каком-либо конкретном порядке. Поскольку входные файлы сжаты, загрузка их занимает больше времени, и они не могут быть прочитаны 1 байт за раз. В итоге я получаю байтовый массив каждого входного файла.

Входные файлы около ~ 1-6 МБ несжатого и ~.3-1 МБ сжатого (сжатие с потерями). Выходные файлы в конечном итоге являются количеством входных файлов в байтах. ~ 36 КБ в моем примере.

Я знаю, что ulimit можно установить на ОС Linux, и эквивалент может быть сделан на окнах. Несмотря на то, что этот номер может быть поднят, я не думаю, что любая ОС будет напоминать миллионы файлов, которые будут написаны одновременно.

Мое текущее решение состоит в том, чтобы сделать 3000 потоковых потоков буферизованного потока и загружать каждый входной файл по очереди и записывать от 1 байт до 3000 файлов, а затем закрывать файл и загружать следующий вход. С этой системой каждый входной файл должен быть открыт примерно по 500 раз.

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

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

Я думаю, что решение будет состоять в том, чтобы буферизовать то, что я могу, из входных файлов (поскольку ограничения памяти не позволяют буферизировать все это), а затем последовательно записывать файлы, а затем делать это снова и снова.

Однако я не знаю, есть ли лучшее решение, используя что-то, о чем я не читаю.

EDIT Я благодарен за быстрый ответ. Я знаю, что я расплывчатый в применении того, что я делаю, и я попытаюсь исправить это. У меня в основном есть трехмерный массив [изображения] [X] [Y] Я хочу перебирать каждое изображение и сохранять каждый цвет с определенного пикселя на каждом изображении и делать это для всех изображений. Проблемы связаны с ограничениями памяти.

byte [] pixels = ((DataBufferByte) ImageIO.read(fileList.get(k)).getRaster(). getDataBuffer()). getData();

Это то, что я использую для загрузки изображений, потому что он выполняет декомпрессию и пропускает заголовок.

Я не редактирую его как видео, потому что мне нужно будет получить фрейм, а затем превратить его в изображение (дорогостоящее преобразование цветового пространства), а затем преобразовать его в байт [], чтобы получить пиксельные данные в цветовом пространстве RGB.

Я мог загружать каждое изображение и разбивать его на ~ 500 частей (размер Y) и записывать в отдельные файлы, которые я оставляю открытыми и записываю для каждого изображения. Выходы будут легко доступны на концерте. Полученный файл может быть полностью загружен в память и превращен в массив для последовательной записи файлов.

Промежуточные шаги означают, что я мог бы разделить нагрузку на сеть, но я пытаюсь сделать это на недорогом ноутбуке с 4 ГБ оперативной памяти, без графического процессора и с низким качеством i7.

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

спросил(а) 2016-04-28T00:12:00+03:00 4 года, 7 месяцев назад
1
Решение
101

Трехфазное управление:

Первый этап: чтение всех входных файлов по одному и запись в один выходной файл. Выходной файл будет ориентирован на запись - скажем, 8-байтовые записи, 4 байта "смещение символов" и 4-байтовый "код-символ". Когда вы читаете файл, смещение символов начинается с 0, конечно, поэтому, если входной файл "ABCD" вы пишете (0, A) (1, B) (2, C) (3, D), Каждый входной файл открывается один раз, считывается последовательно и закрывается. Выходной файл открывается один раз, записывается последовательно, затем закрывается.

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

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

Вуаля! Вам нужно пространство для промежуточного файла и хороший внешний вид (и пространство для его рабочих файлов).

Как предполагает @Jorge, как фаза 1, так и фаза 2 могут быть распараллелены, и на самом деле такая работа, как указано (этапы 1-3), находится именно в точке сложения mapreduce/hadoop.

ответил(а) 2016-04-28T00:24:00+03:00 4 года, 7 месяцев назад
71

Вы очень расплывчаты там, но, может быть, взгляд на mapreduce может помочь. Кажется, что такая работа может быть распределена.

С дополнительной информацией, которую вы предоставили, я действительно не вижу, как выполнить эту задачу на общем оборудовании, таком как 4GB i7, о котором вы говорили. Ваша проблема выглядит как алгоритм укладки изображений, чтобы получить достойное изображение из множества не очень хороших изображений, типичной проблемы в обработке астрономических изображений, и я уверен, что он применяется к другим областям. Хороший поиск в обработке астрономических изображений может быть хорошим использованием вашего времени, есть программное обеспечение под названием registax (не уверен, что оно все еще существует), что делает что-то подобное, но с видеофайлами.

Выполняя некоторую математику салфетки, если вы займете 1 секунду, чтобы открыть файл, вы получите 10-часовую стоимость всего открытия файла.

Подходом было бы получить некоторый диск FAST (SSD), я бы распаковал все файлы в какой-то необработанный формат и сохранил их на диске, оттуда вам придется использовать указатели файлов для чтения непосредственно из файлов, не получая их в память и записать вывод в файл прямо на диск.

ответил(а) 2016-04-28T00:25:00+03:00 4 года, 7 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема