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



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

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

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

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

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

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

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

系统内存不足错误

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

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

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

我想使用一种提取方法,如果line1=line2,从文件中提取那一行,但我不知道如何在代码中写入。

有人知道该按我的要求做吗?

要按顺序比较行,文件必须已经排序。要对大文件进行排序,可以使用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. 为了使其性能接近可接受,您需要首先对内容进行排序,以启用二进制搜索。您可以通过制作一种算法来实现这一点,该算法从前到后读取文件,并在任何两个连续的行出现故障时交换它们,重复直到排序。或者你可以使用这个: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[],读取该字节偏移量处的行,然后使用二进制搜索在另一个文件中找到相应的条目。如果找不到任何东西,请将差异写入第三个文件,即差异文件。

请参阅StreamReader的ReadLine方法:

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

另外,请参阅此处的一些教程,并特别注意此处的"使用"(比显式使用try/finaly和Dispose更好阅读):

http://www.dotnetperls.com/streamreader

相关内容

  • 没有找到相关文章

最新更新