Разделение текстового файла без чтения - PullRequest
5 голосов
/ 24 ноября 2011

Есть ли способ, чтобы я мог разбить текстовый файл в Java, не читая его?

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

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

Ответы [ 6 ]

2 голосов
/ 24 ноября 2011

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

1 Reader Thread (читает файл и кормит рабочих)

  • Очередь с прочитанными блоками

1..n Рабочие потоки (n зависит от ядер вашего процессора, обрабатывает блоки данных из потока считывателя)

  • Очередь или словарь с обработанными кусками

1 Writer Thread (записывает результаты в некоторый файл)

Возможно, вы могли бы объединить поток Reader / Writer в один поток, потому что не имеет смысла распараллеливать IO на одном физическом жестком диске.

Понятно, что вам нужны вещи для синхронизации между потоками. Специально для очередей подумайте о семафорах

2 голосов
/ 24 ноября 2011

С технической точки зрения - это невозможно сделать без чтения файла. Но вам также не нужно хранить все содержимое файла в памяти, чтобы выполнить разбиение. Просто откройте поток в файл и запишите в другие файлы, перенаправив вывод в другой файл после того, как определенное количество байтов записано в один файл. Таким образом, вы не обязаны хранить более одного байта данных файла в памяти в любой момент времени. Но, имея больший буфер, около 8 или 16 КБ резко увеличат производительность.

2 голосов
/ 24 ноября 2011

Я не думаю, что это возможно по следующим причинам:

  1. Как вы пишете файл, не «читая» его?
  2. Вам нужно прочитать текст, чтобы узнать, где находится граница символа (кодировка не обязательно равна 1 байту). Это означает, что вы не можете рассматривать файл как двоичный файл.

Неужели невозможно читать построчно и обрабатывать это так? Это также экономит дополнительное пространство, которое разделяемые файлы будут занимать вместе с оригиналом. Для справки, чтение текстового файла просто:

public static void loadFileFromInputStream(InputStream in) throws IOException {
  BufferedReader inputStream = new BufferedReader(new InputStreamReader(in));

  String record = inputStream.readLine();
  while (record != null) {
    // do something with the record
    // ...
    record = inputStream.readLine();
  }
}

Вы читаете только одну строку за раз ... поэтому размер файла не влияет на производительность вообще. Вы также можете остановиться в любое время. Если вы любите приключения, вы также можете добавить строки в отдельные потоки, чтобы ускорить обработку. Таким образом, IO может продолжать работать, пока вы обрабатываете свои данные.

Удачи! Если по какой-то причине вы нашли решение, пожалуйста, опубликуйте его здесь. Спасибо!

2 голосов
/ 24 ноября 2011

Без чтения содержимого файла вы не сможете этого сделать. Это невозможно.

1 голос
/ 24 ноября 2011

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

Тем не менее, я думаю, что вы действительно хотите знать, если у вас могут быть разные потоки, последовательно читающие разные «части» файла одновременно. И ответ в том, что вы можете сделать это. Просто попросите каждый поток создать свой собственный объект RandomAccessFile для файла, seek в соответствующем месте и начать чтение.

(FileInputStream, вероятно, тоже будет работать, хотя я не думаю, что спецификация Java API гарантирует , что skip реализован с использованием операции поиска уровня файла для файла.)

Есть несколько возможных осложнений:

  • Если файл является текстовым, вы, вероятно, хотите, чтобы каждый поток начинал обработку в начале какой-либо строки в файле. Таким образом, каждый поток должен начинаться с поиска конца строки и убедиться, что он читает до конца последней строки в своей «части».

  • Если файл использует кодировку символов переменной ширины (например, UTF-8), то вам нужно разобраться со случаем, когда границы вашего раздела попадают в середину символа.

1 голос
/ 24 ноября 2011

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

Если вы работаете на машине с Linux, вы можете делегировать разделениена внешнюю команду, такую ​​как csplit .Так что ваша Java-программа просто запустит команду csplit yourbigfile.txt.

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