2015-08-27 2 views
1

Возможно ли иметь функцию, которая вернет x строк файла с конца? Функция будет принимать параметр определяет, как далеко от конца мы хотим читать (в строках меры) и сколько строк мы хотим быть возвращены из этой позиции:строки списка erlang с позиции из конца файла

get_lines_file_end(IoDevice, LineNumberPositionFromEnd, LineCount) -> 

Пример: У нас есть файл с 30 строками 0 -29

get_lines_file_end(IoDevice, -10, 10) // will return lines 20-29 
get_lines_file_end(IoDevice, -20, 10) // will return lines 10-19 

проблема в том, что я могу искать только файла: позиция по определенному количеству байт ..

Цель: Просмотр файлов большого журнала (сотни МБ) страницы образом, начиная с последней «страницы». Erlang используется для отдыха api, который используется веб-сайтом javascript.

Использование такой функции - просмотр всех файлов журналов по страницам, где страница представлена ​​x строками текста. Никакая обработка файлов журналов или получение определенной информации не требуется.

Благодаря

+1

Каков фактический вопрос? –

+0

вопрос: как я могу получить строки текста с заданной позицией файла, но с их перечислением с конца файла. Я вижу, что мне нужно упростить текст, о котором идет речь. – nayana

+0

@AdamLindberg ok Я полностью отреставрирован вопрос и упрощен до одного вопроса .. – nayana

ответ

3

Две точки должны быть сделаны:

  1. Чтобы сделать это вы должны создать метаданные о содержимом текстового файла, чтобы амортизировать работу. Таким образом, вы можете напрямую пропустить бит, который вам нужен, запросив с помощью file:position/2после, вы создали эти метаданные.
  2. Если это ваш прецедент, вы должны разделить работу по-разному. Огромные текстовые файлы должны быть разбиты на более мелкие текстовые файлы, или (более вероятно), что вы не должны использовать текстовые файлы вообще. В зависимости от вашей цели (что вы не упомянули, я сильно подозреваю, что это проблема X-Y), вы, вероятно, не хотите текст вообще, а скорее хотите знать что-то, представленное текстом. Это может быть хорошей идеей, чтобы сохранить исходный текст где-то на всякий случай, но для фактической обработки данных это почти наверняка лучшая идея для создания символических данных, которые (гораздо более кратко) представляют все, что вам интересно узнать о данных, и хранить это в базе данных, где поиск, сканирование, индексирование и выполнение любых других вещей, которые могут потребоваться, - это естественные операции.

Для создания метаданных о файлах, вам нужно будет сделать что-то аналогичное:

1> {ok, Data} = file:read_file("TheLongDarkTeaTimeOfTheSoul.txt"). 
{ok,<<"Douglas Adams. The Long Dark Tea-Time of the Soul\r\n\r\n"...>>} 
2> LineEnds = binary:matches(Data, <<"\r\n">>).     
[{49,2}, 
{51,2}, 
{53,2}, 
{...}|...] 

А затем сохранить LineEnds где-то отдельно, как мета о самом файле. Использование этого поиска в файлах данных является элементарным (например, использовать file:position/2 с данными в строкеbreak X или length(LineEnds) - X или что-то еще).

Но это все еще глупо.

Если вы хотите прыгать в лог-файлах, и особенно если вы хотите найти в них шаблоны, посчитайте некоторые их аспекты и т. Д.то вы почти наверняка лучше прочитали бы их в базу данных, такую ​​как Postgres, за строкой, подсчитывая номера строк по мере их поступления. В этот момент разбиение на страницы становится тривиальной проблемой.

Журнальные файлы, однако, обычно заполнены данными, которые лучше всего представлены символами, а не фактическим текстом, и, вероятно, еще более предпочтительной идеей является токенизация файла журнала. Рассмотрим случай файлов журнала доступа. Повторяющееся количество посетителей получает доступ из конечного числа точек доступа (IP-адресов, устройств или любого другого) произвольным числом раз. Каждый аспект этого можно отдельно индексировать и сравнивать довольно тривиально в базе данных. Сама же токенизация довольно тривиальна. Мало того, что это решение много быстрее, когда дело доходит до более позднего анализа данных, но оно естественным образом отвечает на ответ очень сложно ответить на вопросы о содержимом данных в очень прямолинейном и знакомом виде. ... И вам даже не нужно терять какие-либо необработанные данные или промежуточные этапы обработки (которые могут быть независимо полезны по-разному).

Также ... обратите внимание, что все вышеуказанные работы могут быть легко выполнены параллельно в Эрланге. Независимо от ситуации с вашими вычислительными ресурсами, написание решения, которое наилучшим образом использует ваше оборудование, безусловно, находится в пределах понимания (при условии, что у вас достаточно общих данных, что это даже проблема).

Как и многие «Как сделать X с данными Y?» вопросы, настоящий ответ всегда будет вращаться вокруг «Какова ваша цель в отношении данных и почему?»

+0

привет, спасибо за изнурительный ответ, мне нравится идея индексирования строк новой строки и/или токенизация конкретной информации. Я ожидал ответа, что это невозможно. При некотором фоне непрерывной обработки новых строк это может сработать. Я просто попытался выполнить: совпадения на 400 МБ-файле, и потребовалось 10 минут обработки и не закончил - он поел, как 4 ГБ ОЗУ, и начал заменять, чтобы я его отговорил .. но надеюсь, что он будет работать – nayana

+0

@otopolsky Если ваши файлы настолько большой, что я бы рекомендовал написать небольшую программу-загрузчик, чтобы прочитать их в базе данных, по одной строке в каждой строке, чтобы сохранить некоторые метаданные по вашему пути (какой файл был и какая строка). Оттуда вы можете делать все, что хотите, намного легче, чем напрямую загружать 400 МБ + кубики токенизированных данных в виртуальную машину, чтобы вытащить определенный сегмент. – zxq9

+0

@otopolsky Привет, снова вам нужен способ сделать это в постоянном пространстве, беспокоил меня ... поэтому я ударил (очень уродливую, но функциональную) демонстрацию того, как это можно сделать в постоянном пространстве, и оно работает на этом дерьмовом ноутбук за 14 секунд в нескольких сотнях мегабайт (я думаю, не слишком тщательно проверял). Слишком уродливо, чтобы вставить выше, так что [здесь ссылка] (http://zxq9.com/archives/1056). Надеюсь, это даст вам некоторые идеи! – zxq9

0

Вы можете использовать file:read_line/1 function читать строки, отбрасывая те, которые не соответствуют диапазон:

get_lines(File, From) when From > 0 -> 
    get_lines(File, file:read_line(File), From, 1). 

get_lines(_File, eof, _From, _Current) -> 
    []; 
get_lines(File, {ok, _Line}, From, Current) when Current < From -> 
    get_lines(File, file:read_line(File), From, Current + 1); 
get_lines(File, {ok, Line}, From, Current) -> 
    [Line|get_lines(File, file:read_line(File), From, Current + 1)]; 
get_lines(_IoDevice, Error, _From, _Current) -> 
    Error. 
+2

Это будет очень неэффективно для нескольких файлов GB, если нужны последние 10 строк. –

+0

да это было бы очень неэффективно, но спасибо .. в моем вопросе я упомянул, что мне нужно установить позицию из конца файла. Можно ли переписать этот код для чтения строк назад с конца файла? было бы лучше, если бы мы могли как-то искать, потому что с большей переменной От ответа потребуется больше времени и дольше – nayana