C# 快速比较两个巨大文本文件的内容

C# 快速比较两个巨大文本文件的内容,c#,.net,C#,.net,我基本上想做的是比较两个巨大的文本文件,如果它们匹配,写出一个字符串,我写了这个,但速度非常慢。我希望你们能有个更好的主意。在下面的示例中,我将比较collect[3]splitfound[0] string[] collectionlist = File.ReadAllLines(@"C:\found.txt"); string[] foundlist = File.ReadAllLines(@"C:\collection_export.txt");

我基本上想做的是比较两个巨大的文本文件,如果它们匹配,写出一个字符串,我写了这个,但速度非常慢。我希望你们能有个更好的主意。在下面的示例中,我将比较collect[3]splitfound[0]

        string[] collectionlist = File.ReadAllLines(@"C:\found.txt");
        string[] foundlist = File.ReadAllLines(@"C:\collection_export.txt");
        foreach (string found in foundlist)
        {
            string[] spltifound = found.Split('|');
            string matchfound = spltifound[0].Replace(".txt", ""); ;
            foreach (string collect in collectionlist)
            {
                string[] splitcollect = collect.Split('\\');
                string matchcollect = splitcollect[3].Replace(".txt", "");
                if (matchcollect == matchfound)
                {
                    end++;
                   long finaldest = (start - end);
                   Console.WriteLine(finaldest);
                    File.AppendAllText(@"C:\copy.txt", "copy \"" + collect + "\" \"C:\\OUT\\" + spltifound[1] + "\\" + spltifound[0] + ".txt\"\n");
                    break;
                }



            }

        }
对不起,那些模糊不清的家伙

我想做的是简单地说,如果一个文件中的内容存在于另一个文件中,那么写出一个字符串(字符串并不重要,只是找到两个比较项的时间很重要)。collectionlist是这样的:
苹果农场

foundlist是这样的
C:\cow\horse\turtle.txt
C:\cow\pig\apple.txt

我正在做的是从collectionlist中提取apple,并在foundlist中找到包含apple的行。然后写出一个基本的windows复制批处理文件。很抱歉给你带来了困惑

答案(全部归功于熔渣)


首先,我建议对两个文件进行规范化,并将其中一个文件放在一个集中。这允许您快速测试是否存在特定行,并将复杂性从O(n*n)降低到O(n)

此外,您不应该在每次写一行时打开和关闭文件:

File.AppendAllText(...); // This causes the file to be opened and closed.

在操作开始时打开输出文件一次,向其写入行,然后在写入所有行后关闭它。

首先,我建议规范化两个文件,并将其中一个文件放入一个集中。这允许您快速测试是否存在特定行,并将复杂性从O(n*n)降低到O(n)

此外,您不应该在每次写一行时打开和关闭文件:

File.AppendAllText(...); // This causes the file to be opened and closed.

在操作开始时打开输出文件一次,向其写入行,然后在写入所有行后关闭它。

您有一个笛卡尔积,因此索引一侧而不是进行增强线性搜索是有意义的


从一个文件中提取密钥,并使用Set或SortedList数据结构保存密钥。这将使查找速度大大加快。(您的整体算法将是O(N lg N)而不是O(N**2))

您有一个笛卡尔积,因此索引一侧而不是进行增强线性搜索是有意义的

从一个文件中提取密钥,并使用Set或SortedList数据结构保存密钥。这将使查找速度大大加快。(您的整体算法将是O(N lg N)而不是O(N**2))

  • 调用(.NET 4)而不是(.NET 2.0)。
    ReadAllLines
    需要构建一个数组来保存返回值,这对于大文件来说可能非常慢。
    如果您没有使用.Net 4.0,请将其替换为StreamReader

  • 使用
    matchCollect
    s(一次)构建一个
    Dictionary
    ,然后在
    foundList
    中循环,检查HashSet是否包含
    matchFound

    这允许您使用O(1)哈希检查替换O(n)内部循环

  • 使用StreamWriter而不是调用
    AppendText

  • EDIT:调用
    Path.GetFileNameWithoutExtension
    和其他
    Path
    方法,而不是手动操作字符串

例如:

var collection = File.ReadLines(@"C:\found.txt")
    .ToDictionary(s => s.Split('\\')[3].Replace(".txt", ""));

using (var writer = new StreamWriter(@"C:\Copy.txt")) {
    foreach (string found in foundlist) {
        string splitFound = found.Split('|');
        string matchFound = Path.GetFileNameWithoutExtension(found)

        string collectedLine;
        if (collection.TryGetValue(matchFound, collectedLine)) {
            end++;
            long finaldest = (start - end);
            Console.WriteLine(finaldest);
            writer.WriteLine("copy \"" + collectedLine + "\" \"C:\\OUT\\" 
                           + splitFound[1] + "\\" + spltifound[0] + ".txt\"");
        }
    }
}
  • 调用(.NET 4)而不是(.NET 2.0)。
    ReadAllLines
    需要构建一个数组来保存返回值,这对于大文件来说可能非常慢。
    如果您没有使用.Net 4.0,请将其替换为StreamReader

  • 使用
    matchCollect
    s(一次)构建一个
    Dictionary
    ,然后在
    foundList
    中循环,检查HashSet是否包含
    matchFound

    这允许您使用O(1)哈希检查替换O(n)内部循环

  • 使用StreamWriter而不是调用
    AppendText

  • EDIT:调用
    Path.GetFileNameWithoutExtension
    和其他
    Path
    方法,而不是手动操作字符串

例如:

var collection = File.ReadLines(@"C:\found.txt")
    .ToDictionary(s => s.Split('\\')[3].Replace(".txt", ""));

using (var writer = new StreamWriter(@"C:\Copy.txt")) {
    foreach (string found in foundlist) {
        string splitFound = found.Split('|');
        string matchFound = Path.GetFileNameWithoutExtension(found)

        string collectedLine;
        if (collection.TryGetValue(matchFound, collectedLine)) {
            end++;
            long finaldest = (start - end);
            Console.WriteLine(finaldest);
            writer.WriteLine("copy \"" + collectedLine + "\" \"C:\\OUT\\" 
                           + splitFound[1] + "\\" + spltifound[0] + ".txt\"");
        }
    }
}


那里的代码似乎不仅仅是简单的文本比较,如果这些文件确实很大,那么
ReadAllLines
将因内存不足而失败。档案有多大?你在寻呼吗?一个大约有一百万行,另一个大约有200K如果两个文本文件的行数不同,那么它们永远不会相同/匹配,是吗?@Frederik:他不是在比较文件是否相等,而是在解析每个文件中的一个列表,然后计算列表的交集。阅读问题,不仅仅是标题。你的代码似乎不仅仅是一个简单的文本比较,如果这些文件真的很大,那么
ReadAllLines
将因内存不足而失败。档案有多大?你在寻呼吗?一个大约有一百万行,另一个大约有200K如果两个文本文件的行数不同,那么它们永远不会相同/匹配,是吗?@Frederik:他不是在比较文件是否相等,而是在解析每个文件中的一个列表,然后计算列表的交集。阅读问题,不仅仅是标题。谢谢,我会尝试一下,我做了一次编辑来澄清我的意思,但我认为你100%同意你的回答。这给了我错误2。参数2必须在string collectedLine处用'out'关键字传递;因此,我改为if(collection.TryGetValue(matchFind,out collectedLine)),但在调试时,它给了我一个具有相同密钥的项,并且该项已被添加。@Mike:您的文件中有重复的项。你需要弄清楚你想如何处理它们;您可能应该在第二个循环中弹出字典并检查密钥是否已经存在;应该是吧?再次为代码中的模糊collectedLine返回null表示抱歉。谢谢,我会尝试一下,我做了一次编辑以澄清我的意思,但我认为你100%同意你的回答。这给了我错误2。参数2必须在st处用“out”关键字传递