C++ 使用多行条目解析日志文件
我正在从第三方应用程序解析一个大小合理的日志文件(最高可达50Mb,此时它会被包装),以便检测在指定时间范围内发生的密钥字符串。此日志文件中的典型条目可能如下所示C++ 使用多行条目解析日志文件,c++,c,winapi,C++,C,Winapi,我正在从第三方应用程序解析一个大小合理的日志文件(最高可达50Mb,此时它会被包装),以便检测在指定时间范围内发生的密钥字符串。此日志文件中的典型条目可能如下所示 DEBUG 2013-10-11@14:23:49 [PID] - Product.Version.Module (Param 1=blahblah Param2=blahblah Param3 =blahblah Method=funtionname) String that we usually don't care about
DEBUG 2013-10-11@14: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
条目之间用空行分隔(\r\n在条目末尾,然后在下一个条目开始之前)
这是针对特定于Windows的实现,因此不需要可移植,可以是C/C++/Win32
逐行读取此内容将非常耗时,但其好处是能够解析时间戳并在检查条目中是否存在任何键字符串之前检查条目是否在给定的时间范围内。如果我用块读取文件,我可能会发现一个Kig字符串,但是块没有更早的时间戳,或者块边界甚至可能在KEYSHIPE字符串的中间。将整个文件读入内存并对其进行解析不是一个选项,因为作为其一部分的应用程序目前占用的空间相对较小,因此无法证明仅为解析文件(即使是暂时的)就将其增加10倍。是否有一种方法可以通过分隔块(特别是“\r\n\r\n”)读取文件?或者有没有其他/更好的方法我没有想到
在此方面的任何帮助都将不胜感激
另一个可能考虑的是,是否可以在后台进行一些工作,以生成文件的索引,并在实际需要结果时使用索引。索引将(例如)在写入后立即读取每个条目的时间戳(例如,使用
ReadDirectoryChangesW
在修改日志文件时被告知)。例如,它将文本时间戳转换为时间,然后在索引中存储一个条目,给出该条目的时间和文件偏移量。这应该足够小(对于一个50兆字节的日志文件来说,可能低于1兆字节),以便完全在内存中使用它。一个可能的解决方案是使用内存映射文件。我个人从来没有用过它们,除了玩具应用,但我知道它背后的一些理论
从本质上讲,它们提供了一种访问文件内容的方式,就像它们是内存一样,我相信它的作用类似于虚拟内存,因此所需的部分将根据需要进行分页,然后在某个时候进行分页(您应该阅读文档,以了解其背后的规则)
在伪代码中(因为我们都喜欢伪代码),您可以按照以下思路进行操作:
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);
我现在很抱歉没有给出非常好的建议,但是相反,Windows提供了很多处理内存的功能,而且大部分都值得一读。1)内存无法使用,主要是因为应用程序会检测到何时使用了太多内存,并会自动重新启动。一种内置机制,用于防止内存泄漏失控。使用额外的50Mb内存肯定会触发此问题。2) 您的意思是将一个块(比如1Mb)读入一个istream,然后对其调用getline()?如果是这样,如果缓冲区边界位于时间戳和我要查找的字符串之间,会发生什么情况?我是否可以从缓冲区的开始到时间戳清除所有内容,然后从文件的下一部分再次填充缓冲区?不幸的是,我没有抓取一个已达到50Mb限制的日志文件,以查看是否“包装”实际上是一个滚动文件,或者它确实在文件的开头重新包装并开始写入。我假设前者,如果它确实是一个滚动文件,那么二进制搜索肯定会很好。我只需要更加熟悉可用的IO功能,因为我在这方面的知识相当有限