Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用多行条目解析日志文件_C++_C_Winapi - Fatal编程技术网

C++ 使用多行条目解析日志文件

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

我正在从第三方应用程序解析一个大小合理的日志文件(最高可达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 but may be KEY_STRING  
条目之间用空行分隔(\r\n在条目末尾,然后在下一个条目开始之前)

这是针对特定于Windows的实现,因此不需要可移植,可以是C/C++/Win32

逐行读取此内容将非常耗时,但其好处是能够解析时间戳并在检查条目中是否存在任何键字符串之前检查条目是否在给定的时间范围内。如果我用块读取文件,我可能会发现一个Kig字符串,但是块没有更早的时间戳,或者块边界甚至可能在KEYSHIPE字符串的中间。将整个文件读入内存并对其进行解析不是一个选项,因为作为其一部分的应用程序目前占用的空间相对较小,因此无法证明仅为解析文件(即使是暂时的)就将其增加10倍。是否有一种方法可以通过分隔块(特别是“\r\n\r\n”)读取文件?或者有没有其他/更好的方法我没有想到

在此方面的任何帮助都将不胜感激

  • 确保你不能使用记忆,也许你有点太“偏执”?过早优化等等
  • 逐行阅读(因为这样可以更容易地分离条目),但要用缓冲读取来包装行读取,一次读取尽可能多的内容,可能是1MB。这可以最大限度地减少磁盘I/O,这通常有利于提高性能
  • 假设(通常情况下)文件中的所有条目按时间顺序排列,您应该能够使用二进制搜索的变体来找到正确的起点和终点,然后解析中间的数据

    基本思想是查找文件的中间部分,然后读取几行,直到找到以“DEBUG”开头的一行,然后读取时间戳。如果时间比你关心的时间早,那么向前看3/4分。如果比你关心的时间晚,回到1/4。做记号重复基本想法,直到找到开始。然后在结束时间做同样的事情

    一旦搜索量下降到某个阈值以下(例如,64K),搜索64K对齐块的开头可能会更快,只需从那里继续向前读取,而不必再进行搜索


    另一个可能考虑的是,是否可以在后台进行一些工作,以生成文件的索引,并在实际需要结果时使用索引。索引将(例如)在写入后立即读取每个条目的时间戳(例如,使用

    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功能,因为我在这方面的知识相当有限