在二进制文件中搜索字符串的代码

Posted

技术标签:

【中文标题】在二进制文件中搜索字符串的代码【英文标题】:Code for searching for a string in a binary file 【发布时间】:2011-09-23 04:20:42 【问题描述】:

几天前我问过这个问题:

How to look for an ANSI string in a binary file?

我得到了一个非常好的answer,后来变成了一个更难的问题:Can input iterators be used where forward iterators are expected? 现在真的没有达到我能理解的水平。

我还在学习 C++,我正在寻找一种在二进制文件中搜索字符串的简单方法。

谁能给我看一个简单的 C++ 控制台程序的简单代码,它在二进制文件中查找字符串并将位置输出到标准输出?

可能,你能告诉我

    文件被复制到内存的版本(假设二进制文件很小)

    另一个使用链接问题中的正确方式

很抱歉,这听起来像是我在询问某人的代码,但我只是在学习 C++,我认为如果有人可以发布一些值得学习的高质量代码,其他人可能会从这个问题中受益。

【问题讨论】:

“位置”是什么意思? 第一个字符的字节,从文件开头开始计数。我的意思是告诉() Boyer-Moore algorithm(另见portal.acm.org/citation.cfm?doid=360825.360855) 【参考方案1】:

您的需求规范不清楚,例如 - “121”出现在“12121”中的什么位置......只是在第一个字符处(之后在第 4 个字符处继续搜索),还是在第 3 个字符处?下面的代码使用了前一种方法。

#include <iostream>
#include <fstream>
#include <string>
#include <string.h>

int main(int argc, const char* argv[])

    if (argc != 3)
    
        std::cerr << "Usage: " << argv[0] << " filename search_term\n"
            "Prints offsets where search_term is found in file.\n";
        return 1;
    

    const char* filename = argv[1];
    const char* search_term = argv[2];
    size_t search_term_size = strlen(search_term);

    std::ifstream file(filename, std::ios::binary);
    if (file)
    
        file.seekg(0, std::ios::end);
        size_t file_size = file.tellg();
        file.seekg(0, std::ios::beg);
        std::string file_content;
        file_content.reserve(file_size);
        char buffer[16384];
        std::streamsize chars_read;

        while (file.read(buffer, sizeof buffer), chars_read = file.gcount())
            file_content.append(buffer, chars_read);

        if (file.eof())
        
            for (std::string::size_type offset = 0, found_at;
                 file_size > offset &&
                 (found_at = file_content.find(search_term, offset)) !=
                                                            std::string::npos;
                 offset = found_at + search_term_size)
                std::cout << found_at << std::endl;
        
    

【讨论】:

@ildjarn: true(但是,在我的基准测试中,它的运行速度仍然是您的非增强解决方案的 两倍以上 ;-P) 很公平,我对您的结果进行了基准测试并验证了;我没想到从istreambuf_iterator 对复制这么慢。 :-[ @ildjarn:你的代码发生了什么?即使它不是最快的解决方案,它也可能是一个非常好的参考!我计划从所有 4 个解决方案中学习。 @ildjarn:zsero 是对的......你有很好的解决方案可以列出......这可能很简单,比如不在双端队列上使用保留 - 我没有时间调查 - 但这不是无论如何,它可能会在其他人/未来的库实现等中运行得更快......【参考方案2】:

这是完成第 1 部分的一种方式。我不确定我是否会将其描述为高质量,但可能是极简主义。

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main(int argc, char *argv[])

    std::ifstream ifs(argv[1], ios::binary);

    std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

    size_t pos = str.find(argv[2]);

    if (pos != string::npos)
        cout << "string found at position: " << int(pos) << endl;
    else
        cout << "could not find string" << endl;

    return 0;

【讨论】:

谢谢,工作完美,读起来真的很不错!但我的问题是 std::string str (std::istreambuf_iterator, std::istreambuf_iterator) 非常慢。而实际搜索几乎不需要时间就能找到结果。有什么方法可以更快地创建字符串? @zsero - 迭代器很慢。更快的方法是 (1) 读取数据缓冲区并进行搜索,而不是将整个文件读入内存,所有这些都可能不是必需的; (2) 下拉到更多特定于操作系统的内容,如内存映射或使用操作系统提示,如 posix_fadvise。简单地使用一个好的缓冲区大小和 fstream.read() 会比这更快。

以上是关于在二进制文件中搜索字符串的代码的主要内容,如果未能解决你的问题,请参考以下文章

Java中排序(内存映射?)文件中的二进制搜索

搜索二进制文件中所有出现的字节串

使用vim按十六进制代码搜索

在已排序的文本文件中实现二进制搜索?

最强辅助!IDA 辅助工具Karta——二进制文件中搜索开源代码

我如何在linux / unix / bash脚本中搜索文件中的十六进制内容?