我有一个大的二进制文件(很多千兆字节,因此无法将其加载到内存中)我想搜索所有出现的字符串“icpf”。
我尝试使用std::search
来解决这个问题,但是std::search
仅适用于前向迭代器,而不是输入迭代器。
标准库是否为此提供了快速替代方案?或者我是否需要手动编码搜索(一次读取数据块然后std::search
,或ignore
所有内容直到'i',然后手动检查接下来的三个字符)?< / p>
答案 0 :(得分:1)
最快的方法是将整个文件加载到内存中,然后搜索内存。
下一个最佳选择是让硬盘保持运转状态。也许有一个线程将数据块读入缓冲区,另一个线程则搜索缓冲区。
沿着列表向下,将大块数据读入缓冲区,然后搜索缓冲区是一种很好的技术,尽管效率不如以前的方法。
您可以使用std::getline
和std::string
逐行阅读。这不如块读取快,因为输入函数正在搜索换行符(并在std::string
中分配内存)。
最糟糕的情况可能是逐字逐句阅读。函数开销对于读取单个字符是不好的(通常,读取大块数据的开销是相同的)。
不,没有用于搜索文件的标准C ++库函数。某些操作系统具有搜索文件的实用程序;也许你可以使用其中之一。
编辑1:
瓶颈是输入数据。一旦你将数据放入缓冲区,那么就是许多有效的搜索算法而不是蛮力(搜索第一个字母,然后搜索下一个字母等)。
在互联网上搜索&#34;字符串搜索算法&#34;。
答案 1 :(得分:1)
标准库是否为此提供了快速替代方案?
虽然标准C ++库提供了搜索文本流的方法,但它没有为二进制流提供类似的算法。
或者我是否需要手动编码搜索(一次读取数据块然后
std::search
,或忽略所有内容直到'i'
,然后手动检查接下来的三个字符)?
编写“跳过和搜索”方法可能很棘手,因为编写跳过条目的解决方案很容易。例如,如果您在包含"icpf"
的文件中查找"icpicpf"
,则一次处理一个字符的简单程序在丢弃"icpf"
后将无法找到"icpi"
后缀前缀。
如果您要自己编写代码,请考虑实施Knuth–Morris–Pratt algorithm。网上有很多可用的实现,它可以在流上正确运行,因为它一次只考虑一个字符,而且永远不会回溯。
答案 2 :(得分:0)
我不知道任何纯标准库解决方案,但是内核已经实现了预取,因此应该可以mmap()
该文件来获取所需的前向迭代器:(省略错误处理)< / p>
size_t search(int fd, size_t fileSize) {
auto start = reinterpret_cast<char*>(
::mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0));
::madvise(start, fileSize, MADV_SEQUENTIAL);
auto pattern = "icpf";
auto offset = std::search(start, start+fileSize, pattern, pattern+4);
return offset - start;
}
它是一个小小的信念飞跃,相信你的内核可以正确地进行延迟加载,预取和丢弃。另一方面,如果您可以信任任何人,那么可能是内核开发人员。
免责声明:我实际上并没有在一个千兆字节的文件上测试它。