从大文件中删除冗余数据

时间:2012-11-03 18:17:28

标签: c# sqlite

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

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

有什么想法吗?我的另一个想法是将整个内容输出到SQLite数据库并选择DISTINCT值,但我不确定它是否可以使用那么多值。

感谢您的任何意见!

3 个答案:

答案 0 :(得分:2)

您是否尝试使用数组初始化HashSet。我假设HashSet的加倍算法是OutOfMemoryException的原因。

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

修改

  

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

然后你应该尝试使用文件行的正确(最大)大小初始化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);

答案 1 :(得分:2)

首先需要考虑的是 - 高内存消耗是一个问题吗?

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

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

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

祝你好运。

答案 2 :(得分:1)

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

我从我的Windows 8安装中读取了安装日志,其大小为32MB,大小为312248,并在.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());

perf in linqpad