2013-10-14 3 views
1

Я работаю над анализом файла журнала разумного размера (до 50 МБ, с которого он обертывает) из стороннего приложения, чтобы обнаружить KEY_STRING, которые произошли за указанное время Рамка. Типичная запись в этом файле журнала может выглядеть следующим образомАнализ файла журнала с многострочными записями

DEBUG [email protected]:23:49 [PID] - Product.Version.Module 
(Param 1=blahblah Param2=blahblah Param3 =blahblah 
Method=funtionname) 
String that we usually don't care about but may be KEY_STRING 

Записи разделяются пустой строкой (\ г \ п в конце записи затем \ г \ п до начала следующего входа)

Это для конкретной реализации Windows, поэтому ее не нужно переносить и может быть C/C++/Win32

Чтение этой строки за строкой было бы трудоемким, но было бы полезно проанализировать метку времени и проверьте, находится ли запись в течение заданного периода времени, прежде чем проверять, присутствует ли какая-либо из KEY_STRING в записи. Если я прочитаю файл кусками, я могу найти KEY_STRING, но кусок не имеет более ранней отметки времени, или граница фрагмента может даже находиться в середине KEY_STRING. Чтение всего файла в памяти и разбор его не является вариантом, так как приложение, в котором оно должно быть частью текущего, имеет относительно небольшой размер, поэтому не может оправдать увеличение этого на ~ 10x только для разбора файла (даже временно) , Есть ли способ, которым я могу прочитать файл с помощью разделенных фрагментов (в частности, «\ r \ n \ r \ n»)? Или есть другой/лучший метод, о котором я не думал?

Любая помощь на этом будет принята с благодарностью!

ответ

0

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

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

В псевдокоде (потому что мы все, как псевдокод), вы могли бы сделать что-то вдоль этих линий:

HANDLE file = CreateFile(...); 
HANDLE file_map = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, ...); 
LPVOID mem = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0); 

// at this point you can use mem to access data in the mapped part of the file... 
// for your code, you would perform parsing as if you'd read the file into RAM. 

// when you're done, unmap and close the file: 
UnmapViewOfFile(mem); 
CloseHandle(file_map); 
CloseHandle(file); 

Я извиняться сейчас не давая советы самым прекрасным, но вместо этого encourage further reading - Windows предоставляет множество функций для обрабатывая вашу память, и это в основном стоит прочитать.

0
  1. Удостоверьтесь, что вы не можете использовать память, возможно, вы слишком «параноики»? Преждевременная оптимизация и все такое.
  2. Прочитайте его по строкам (так как это облегчает разделение записей), но оберните чтение строки буферизованным чтением, считая столько за раз, насколько вам удобно, возможно, 1 МБ. Это минимизирует дисковый ввод-вывод, что часто бывает полезно для производительности.
+0

1) Память не может использоваться, прежде всего потому, что приложение обнаруживает, когда оно использует слишком много памяти и перезагружается. Встроенный механизм для предотвращения утечки памяти. Использование дополнительного 50 МБ памяти, безусловно, вызовет это. 2) Под этим вы хотите прочитать фрагмент (например, 1Mb) в istream, а затем называть getline()? Если да, что произойдет, если граница буфера находится между меткой времени и строкой, которую я ищу? Можно ли очистить все с начала буфера до отметки времени, а затем снова заполнить буфер из следующей части файла? – sarmstro

0

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

Основная идея заключалась бы в том, чтобы искать середину файла, затем читать несколько строк, пока вы не начнете с «DEBUG», а затем прочитайте метку времени. Если это раньше, чем время, о котором вы заботитесь, пройдите вперед к отметке 3/4 тыс.. Если позже времени, о котором вы заботитесь, вернитесь к 1/4 th. отметка. Повторите основную идею, пока не найдете начало. Затем сделайте то же самое для конечного времени.

После того, как сумма, по которой вы ищете, падает ниже определенного порога (например, 64K), вероятно, быстрее искать начало блока с выравниванием по 64 КБ и просто продолжать читать вперед, чем делать больше Ищу.

Еще одна возможность рассмотреть вопрос о том, можете ли вы сделать некоторую работу в фоновом режиме, чтобы создать индекс файла по мере его изменения, а затем использовать индекс, когда вам действительно нужен результат. Индекс должен (например) считывать отметку времени каждой записи сразу после ее записи (например, используя , который будет указан при изменении файла журнала). Он преобразует текстовую метку времени, например, в time_t, а затем сохраняет запись в индексе, указывающую time_t и смещение файла для этой записи. Это должно быть достаточно маленьким (вероятно, под мегабайтом для файла журнала размером 50 мегабайт), что было бы легко работать с ним полностью в памяти.

+0

К сожалению, мне не удалось захватить один из файлов журналов, достигший 50-мегабайтного лимита, чтобы увидеть, действительно ли «обертка» представляет собой скользящий файл, или если он буквально завершает и начинает писать в начале файла снова. Я бы предположил, что первый, если он окажется скользящим файлом, тогда двоичный поиск определенно будет приятным. Просто нужно больше ознакомиться с доступными функциями ввода-вывода, поскольку мои знания об этой области довольно ограничены – sarmstro

Смежные вопросы