简化问题:我有两个大文件不能使用字符串数组存储在内存中,也不能使用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
几点:
-
为了使其性能接近可接受,您需要首先对内容进行排序,以启用二进制搜索。您可以通过制作一种算法来实现这一点,该算法从前到后读取文件,并在任何两个连续的行出现故障时交换它们,重复直到排序。或者你可以使用这个:http://www.codeproject.com/Articles/285123/Sorting-Huge-Text-Files
只需要对其中一个文件进行排序。
-
如果文件的格式不是固定宽度(每行的字节数相同),则需要创建一个索引,告诉您每行的起始字节偏移量。如果可能的话,索引应该保存在内存中(如果你想让文件大小大于4GB,这里的List或long[]是理想的)
-
为了获得最佳性能,我建议使用MemoryMappedFile:https://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile(v=vs.110).aspx,用于访问正在读取的两个文件。"视图"的大小应至少为最大线条的大小。
-
一旦对其中一个文件进行了排序(如果不是固定宽度的话,对两个文件都进行了索引),就开始循环遍历未排序文件的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