C#比较大文本文件并写出差异

时间:2016-05-10 15:31:10

标签: c# compare ienumerable

简化问题:我有两个大文件无法使用字符串数组存储在内存中,也不能使用Except方法,因为这也会将文件数据推送到内存中。我的目标是比较两个大文件并吐出差异,但我不能通过将一个大文件加载到内存中来实现。有没有一个好的streamreader逐行解决方案或其他方法来做到这一点?

长问题: 我有两个文件 1. SQLQueryData 2.物理数据

SQLQueryData包含数据库中列出的文件的名称(例如:Recording01.wmv Audiofile01.wma Testrecording.wmv等。)

PhysicalData是物理硬盘上的目录搜索,用于获取其中存在的文件名(这应包含与SQLQueryData相同的信息)。

我故意从他们的目录中删除了这个测试的文件,并制作了数百万个测试名称。 SQLQueryData文件为700MB,PhysicalData大约为650MB。

我首先尝试了string[] readfile = file.readalllines,但这会导致内存不足错误。

我还在两个文件上尝试过IEnumerable<String>,但这会导致

  

系统内存不足错误

因为它将两个文件放入内存中,这很容易占用大约2GB的内存。

我的下一次尝试是只将一个文件加载到内存中,然后使用streamreader来比较单行SQLQueryData与PhysicalData的字符串数组,但这也会导致内存不足错误。

我尝试将流读取器嵌入到另一个流读取器中,但我在网上看到的唯一方法或示例是IF语句,说明流读取器的line1 = line2是否写入该数据。我不想写line1=line2,我需要知道PhysicalData是否包含SQLQueryData信息。

我正在考虑使用一种提取方法,如果line1=line2,从文件中提取该行,但我不知道如何在代码中编写该行。

有人知道我要问的是吗?

3 个答案:

答案 0 :(得分:0)

要按顺序比较行,必须已对文件进行排序。要对大文件进行排序,您可以使用http://classCentric.com/SortHugeFile。以下代码段是http://classCentric.com/SortedDiff工具的一部分,它处理边缘情况,支持正则表达式提取,并允许数字比较。 SortedDiff.cs将testFile与masterFile进行比较,并输出前3行中提到的文件。完整的源代码可以下载。

TextWriter twTest = new StreamWriter("inTestFile.txt");
TextWriter twMaster = new StreamWriter("inMasterFile.txt");
TextWriter twInBoth = new StreamWriter("inBothFiles.txt");
using (StreamReader tr = new StreamReader(testFile))
{
    using (StreamReader mr = new StreamReader(masterFile))
    {
        mLine = mr.ReadLine();

        while ((tLine = tr.ReadLine()) != null)
        {
            if (mLine != null) break;
            //-1: tLine < mLine; 1: tLine > mLine
            comp = String.Compare(tPart, mPart, oStringComparison);

            //while value in test file < that in master, increment test's pointer to process next tLine
            if (comp < 0)
            {
                twTest.WriteLine(tLine);
                continue;
            }

            //while value in test file > that in master, increment master's pointer to process next mLine
            while (comp > 0)
            {
                twMaster.WriteLine(mLine);

                mLine = mr.ReadLine();
                if (mLine == null) break;

                comp = String.Compare(tPart, mPart, oStringComparison);
            }

            if (comp == 0)
            {
                twInBoth.WriteLine(mLine);
                mLine = mr.ReadLine();
            }
            else //comp must be < 0 since "copm > 0" is handled in while & "== 0" after that
            {
                twTest.WriteLine(tLine);
            }
        }//while
    }//using
}//using

答案 1 :(得分:-1)

几点:

  1. 为了使其表现接近可接受,您需要先对内容进行排序以启用二进制搜索。您可以通过制作一个从前到后读取文件的算法来实现这一点,如果它们出现故障则交换任意两条连续的行,重复直到排序。或者你可以使用这个:http://www.codeproject.com/Articles/285123/Sorting-Huge-Text-Files

    只需要对其中一个文件进行排序。

  2. 如果文件的格式不是固定宽度(每行相同的字节数),那么您将需要创建一个索引,告诉您每行的起始字节偏移量。如果可能的话,索引应该保存在内存中(如果你想要文件大小> 4GB,那么List或long []是理想的)

  3. 为了获得最佳性能,我建议使用MemoryMappedFile:https://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile(v=vs.110).aspx来访问您正在阅读的两个文件。视图应至少为最大行的大小。

  4. 一旦你对其中一个文件进行了排序(并且索引了,如果不是固定的宽度,两个文件),开始循环遍历未分类文件的long [],读取该字节偏移的行,然后使用二进制搜索在另一个文件中查找相应的条目。如果找不到任何内容,请将差异写入第三个文件,差异文件。

答案 2 :(得分:-2)

请参阅StreamReader的ReadLine方法:

https://msdn.microsoft.com/en-us/library/system.io.streamreader.readline(v=vs.110).aspx

另请参阅此处的一些教程,特别注意&#34;使用&#34;那里(比使用try / finally和显式Dispose更好阅读):

http://www.dotnetperls.com/streamreader