簡體   English   中英

查找字節數組數組是否包含另一個字節數組的最快方法是什么?

[英]What is the fastest way to find if an array of byte arrays contains another byte array?

我有一些非常慢的代碼。 我知道它會是,現在是。 基本上,我正在從一堆目錄中讀取文件。 文件名會更改,但數據不會更改。 為了確定我是否已經讀取了該文件,我正在對其字節進行哈希並將其與已處理文件的哈希列表進行比較。 每個目錄中大約有1000個文件,並且確定每個目錄中的新內容需要大約一分鍾左右(然后處理開始)。 這是基本代碼:

public static class ProgramExtensions
{
    public static byte[] ToSHA256Hash(this FileInfo file)
    {
        using (FileStream fs = new FileStream(file.FullName, FileMode.Open))
        {
            using (SHA256 hasher = new SHA256Managed())
            {
                return hasher.ComputeHash(fs);
            }
        }
    }
    public static string ToHexString(this byte[] p)
    {

        char[] c = new char[p.Length * 2 + 2];

        byte b;

        c[0] = '0'; c[1] = 'x';

        for (int y = 0, x = 2; y < p.Length; ++y, ++x)
        {
            b = ((byte)(p[y] >> 4));

            c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30);

            b = ((byte)(p[y] & 0xF));

            c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30);
        }

        return new string(c);

    }
}

class Program
{
    static void Main(string[] args)
    {
        var allFiles = new DirectoryInfo("c:\\temp").GetFiles("*.*");

        List<string> readFileHashes = GetReadFileHashes();

        List<FileInfo> filesToRead = new List<FileInfo>();

        foreach (var file in allFiles)
        {
            if (readFileHashes.Contains(file.ToSHA256Hash().ToHexString()))
                filesToRead.Add(file);
        }

        //read new files
    }
}

無論如何我可以加快速度嗎?

我相信你可以通過簡單地首先檢查文件大小來存檔最重要的性能改進,如果filesize不匹配,你可以跳過整個文件,甚至不打開它。

您還可以保留已知文件大小的列表,並在文件大小匹配時僅進行內容比較,而不僅僅是保存已知哈希列表。 當filesize不匹配時,您甚至可以避免查看文件內容。

根據文件的一般大小,進一步的改進是值得的:

  • 當第一個字節不同時,要么與早期中止進行二進制比較(保存讀取整個文件,如果文件通常很大,這可能是一個非常顯着的改進,任何哈希算法都會讀取整個文件。檢測第一個字節是不同的使您免於閱讀文件的其余部分)。 如果您的查找文件列表可能包含許多相同大小的文件,那么您可能需要對多個文件進行二進制比較,而是考慮:

  • 以每個1MB的塊為單位進行散列。 首先僅針對查找中預先計算的第一個塊哈希檢查第一個塊。 如果第一個塊相同,則僅比較第二個塊,在大多數情況下,對於不同的文件,將讀數保存在第一個塊之外 當文件很大時,這兩個選項都非常值得。

我懷疑更改散列算法本身(例如,首先檢查按建議執行CRC)會產生任何顯着差異。 您的瓶頸可能是磁盤IO,而不是CPU,因此避免磁盤IO會給您帶來最大的改進。 但是,與性能一樣, 請進行衡量。

然后,如果這仍然不夠(並且只有那時),請嘗試使用異步IO(請記住,順序讀取通常比隨機訪問更快,因此過多的隨機異步讀取會損害您的性能)

  • 創建文件列表
  • 按文件大小排序列表
  • 從列表中刪除具有唯一大小的文件
  • 現在做散列(快速散列首先可能也會提高性能)
  • 使用具有高效搜索功能(散列或二進制搜索)的readFileHashes存儲的數據結構。 我認為HashSet或TreeSet會在這里為您提供更好的服務。

  • 使用適當的校驗和(哈希和)函數。 SHA256是一個加密哈希,可能有點過分。 CRC的計算成本較低,最初用於捕獲無意/隨機的變化(傳輸錯誤),但是對於被設計/意圖隱藏的變化是可接受的。 什么適合您正在掃描的文件之間的差異?

    http://en.wikipedia.org/wiki/List_of_checksum_algorithms#Computational_costs_of_CRCs_vs_Hashes

    通過采樣(例如校驗和=(前10個字節和后10個字節))真正簡單的校驗和是否有效?

我先做一個快速CRC哈希檢查,因為它更便宜。 如果CRC不匹配,繼續進行更“可靠”的哈希測試,例如SHA

您對問題的描述仍然不夠明確。

最大的問題是你正在做一堆哈希。 這保證很慢。

您可能想嘗試搜索修改時間,如果文件名已更改,則修改時間不會更改:

http://msdn.microsoft.com/en-us/library/ms724320(VS.85,loband).aspx

或者,您可能希望監視文件夾以查找任何新文件:

http://www.codeguru.com/forum/showthread.php?t=436716

首先按文件大小對文件進行分組 - 這將為您留下較小的文件組。 現在它取決於組大小和文件大小。 您可以開始並行讀取所有文件,直到找到差異為止。 如果存在差異,請將組拆分為在當前位置具有相同值的較小組。 如果您有關於文件如何不同的信息,您可以使用此信息 - 最后開始閱讀,如果更大的群集更改,或者您對文件的了解,請不要逐字節讀取和比較。 如果您必須並行讀取許多文件導致隨機光盤訪問,此解決方案可能會引入I / O性能問題。

您還可以計算每個組中所有文件的哈希值並進行比較。 您不能一次處理整個文件 - 只需計算一些(可能是4kiB集群或任何適合您的文件大小)字節的散列,並檢查是否存在所有已有的差異。 如果不是,則計算接下來幾個字節的哈希值。 這將使您可以處理每個文件的較大塊,而無需為內存中的組中的每個文件保留一個這樣的大塊。

所以關於時間內存(光盤I / O內存)的權衡。 你必須在將一組中的所有文件讀入內存並逐字節地比較它們之間找到方法(高內存要求,快速順序訪問,但可以讀取大量數據)並逐字節讀取文件並僅比較最后一個字節讀取(低內存要求,慢速隨機訪問,只讀取所需數據)。 此外,如果組非常大,逐字節比較文件將變得更慢 - 比較n個文件中的一個字節是O(n)操作 - 並且首先計算哈希值然后僅比較哈希值可能更有效值。

更新:絕對不要只檢查文件大小。 如果你的os版本允許使用FileInfo.LastWriteTime

我已經為內部項目編譯器/打包器實現了類似的功能。 我們有超過8k的文件,因此我們將最后修改的日期和哈希數據存儲到sql數據庫中。 然后在后續運行中,我們首先查詢任何特定文件上的修改日期,然后才查詢哈希數據...這樣我們只計算那些看似被修改的文件的新哈希數據...

.net有一種方法可以在FileInfo類中檢查上次修改日期..我建議你查看一下。 編輯:這是鏈接LastWriteTime

我們的打包器大約需要20秒才能找出修改過的文件。

暫無
暫無

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

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