2

我有一个日志文件,每行都有一个字符串。我正在尝试从文件中删除重复数据并将文件另存为新文件。我首先想到将数据读入 HashSet,然后将 hashset 的内容保存出来,但是在尝试执行此操作时出现“OutOfMemory”异常(在将字符串添加到 hashset 的行上)。

文件中有大约 32,000,000 行。每次比较都重新读取整个文件是不切实际的。

有任何想法吗?我的另一个想法是将整个内容输出到 SQLite 数据库并选择 DISTINCT 值,但我不确定这是否适用于这么多值。

感谢您的任何意见!

4

3 回答 3

2

您是否尝试过使用数组来初始化HashSet. 我假设 的加倍算法HashSetOutOfMemoryException.

var uniqueLines = new HashSet<string>(File.ReadAllLines(@"C:\Temp\BigFile.log"));

编辑

我正在测试 .Add() 方法的结果,看看它是否返回 false 以计算冗余项目的数量。如果可能的话,我想保留这个功能。

然后你应该尝试HashSet使用文件行的正确(最大)大小来初始化:

int lineCount = File.ReadLines(path).Count();
List<string> fooList = new List<String>(lineCount);
var uniqueLines = new HashSet<string>(fooList);
fooList.Clear();
foreach (var line in File.ReadLines(path))
    uniqueLines.Add(line);
于 2012-11-03T18:25:26.887 回答
2

您需要考虑的第一件事 - 高内存消耗是一个问题吗?

如果您的应用程序将始终在具有大量可用 RAM 的服务器上运行,或者在任何其他情况下您知道您将有足够的内存,那么您可以做很多如果您的应用程序运行在低速运行时无法做到的事情 -记忆环境,或未知环境。如果内存不是问题,请确保您的应用程序作为 64 位应用程序运行(当然,在 64 位操作系统上),否则您将被限制为 2GB 内存(如果您使用 LARGEADDRESSAWARE,则为 4GB旗帜)。我想在这种情况下这是你的问题,你所要做的就是改变它——它会很好用(假设你有足够的内存)。

如果内存有问题,并且您不需要使用太多内存,您可以按照您的建议将所有数据添加到数据库中(我更熟悉 SQL Server 等数据库,但我想 SQLite 会这样做),请确保您在列上有正确的索引,然后选择不同的值。

另一种选择是将文件作为流逐行读取,为每一行计算哈希,并将该行保存到其他文件中,并将哈希保存在内存中。如果散列已经存在,则移动到下一行(如果您愿意,可以添加到删除行数的计数器)。在这种情况下,您将在内存中保存更少的数据(仅用于不重复项的哈希)。

祝你好运。

于 2012-11-03T18:28:16.633 回答
1

我使用 HashSet 对 Tim 采取了类似的方法。我确实添加了手动行计数和比较。

我从我的 Windows 8 安装中读取了安装日志,该日志大小为 58MB,行数为 312248 行,并在 0.993 秒内在 LinqPad 中运行它。

var temp=new List<string>(10000);
var uniqueHash=new HashSet<int>();
int lineCount=0;
int uniqueLineCount=0;

using(var fs=new FileStream(@"C:\windows\panther\setupact.log",FileMode.Open,FileAccess.Read))
    using(var sr=new StreamReader(fs,true)){
        while(!sr.EndOfStream){
        lineCount++;
        var line=sr.ReadLine();
        var key=line.GetHashCode();
            if(!uniqueHash.Contains(key) ){
                uniqueHash.Add(key);
                temp.Add(line);
                uniqueLineCount++;
                    if(temp.Count()>10000){
                        File.AppendAllLines(@"c:\temp\output.txt",temp);
                        temp.Clear();
                    }
            }
        }
    }
Console.WriteLine("Total Lines:"+lineCount.ToString());
Console.WriteLine("Lines Removed:"+ (lineCount-uniqueLineCount).ToString());

linqpad 中的性能

于 2012-11-03T19:52:14.443 回答