簡體   English   中英

C ++搜索算法-處理大量數據

[英]C++ Search Algorithms - Processing Huge Data

我有一個代碼在文件中搜索字符串,文件的大小可以為1mg或1gig或更大。

我使用ReadFile() WinAPI獲取文件數據並轉換為十六進制,然后在轉換后的數據中搜索字符串(之前是十六進制的)。

我使用以下代碼進行搜索(字符串搜索):

std::string searchStr = "48656C6C6FA"
std::string fileData = ToHex(inputString);

if(fileData.find(searchStr, 0) != std::string::npos)
{
    std::cout << FileName;
}

2900個文件中搜索字符串大約需要11秒。

還有其他更快的搜索算法或功能嗎? 這種方式(上面)有時會遺漏字符串,但效果並不理想。

如果您有一個較小的文件(如幾兆字節,甚至幾百兆字節,具體取決於系統擁有的內存量),則將其全部讀取到內存中,否則建議使用內存映射文件 如果要映射的文件太大,則可以使用滑動窗口或雙緩沖算法將數據塊從文件讀取到內存中。

然后,要搜索特定的字節序列,可以對文件的內容進行線性搜索,查找要搜索的序列的第一個字節(對於0x48656C6C6FA0xFA )。 如果找到,則嘗試將序列中的第二個字節(在示例中為0xC6 )與文件中的下一個字節進行匹配,依此類推,直到匹配了整個序列。

如果第二個(或連續的)字節不匹配,則繼續搜索第一個字節。

這具有O(n)復雜度,其中n是文件中的字節數。 除非事先知道要搜索的數據在文件的特定部分中,否則這將是最好的選擇。


如果文件位於SSD上,則可以使用線程搜索,每個文件一個線程。 但是並非同時所有2900個文件都會淹沒處理器。 取而代之的是讓4-8個線程進行搜索(取決於系統的內核數),並且一旦一個線程完成了一個文件,它就會占用下一個線程。

不能在旋轉磁盤驅動器上使用,因為當線程嘗試讀取時,當磁頭來回搜索時,它將破壞磁盤。

速度:使用內存映射文件

精度:使用std :: search使用二進制值。

例如

#include <algorithm>
#include <cstdint>
#include <tuple>
#include <vector>

// some function to return a pointer to the first byte in the file and the length 
extern std::tuple<const std::uint8_t*, std::size_t> get_file_bounds();

int main()
{
    auto [begin, size] = get_file_bounds();
    auto search_string = std::vector<std::uint8_t> {
        0x48,
        0x65,
        0x6C,
        0x6C,
        0x6F
    };

    auto iter = std::search(begin, begin + size, 
                            search_string.begin(), search_string.end());

    if (iter != begin + size)
    {
        // found the sequence 
    }
    else 
    {
        // didn't find it
    }

}

對於與您的搜索字符串一樣短的搜索字符串(顯然是5 1/2字節),瓶頸通常是磁盤I / O。 我懷疑那2900個文件可能在硬盤上。 這相當於每個文件大約4毫秒,這相當不錯。

當然,轉換為十六進制可能有點笨拙,但是考慮到5 1/2字節(11個十六進制數字),這可能並非完全不合理。 也就是說,如果HDD是真正的瓶頸,那么您可能無法獲得重大的速度提升。

因此,要檢查一下,如果搜索2900個fies,而只是讀入它們,則測量一下您花費了多少時間。甚至不要將它們轉換為十六進制。 無論搜索算法多么智能,磁盤I / O所需的時間都是一個下限。 如果這還不夠好,請獲取快速的SSD。

對於更快的字符串搜索算法,請看一下Boyer Moore搜索算法。 Boost(和c ++ 17)具有這樣的實現。

另外,請避免將文件轉換為十六進制(std :: strings可以包含'\\ 0'字符)。

如果文件IO受到限制,則內存映射文件可能是前進的方向。

盡管這可能是一個存儲瓶頸問題,但有些字符串搜索算法可能比線性算法快得多,例如,Boyer Moore(在https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm中進行了介紹)與線性搜索相比,確實需要處理搜索模式並節省一些內存開銷。

基本思想是根據在給定索引處找到的內容來知道可以跳過多少個字符。 (即,從fileData [patternLLen-1]開始,如果字符甚至不在搜索模式中,則可以接下來查看fileData [patternLen + patternLen-1],依此類推。

模式越長,這種算法越可能是對線性搜索的一種改進。 boost庫已經實現了幾種改進的字符串搜索算法的實現(可在boost / algorithm \\ searching /中找到)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM