从大文本文件导入数据库时​​获取SystemOutOfMemoryException的方法

时间:2012-02-25 07:24:36

标签: c# import datatable streamreader bulk

我们正在使用ZyWall来保护我们的服务器免受外部入侵。它生成每日日志文件,其大小超过GB,有时为2 GB。它们通常包含超过1000万行。现在我的任务是编写一个将这些行导入Oracle数据库的应用程序。我是用C#写的。我目前正在做的是:

  1. 我逐行阅读日志文件。我不会立即加载整个文件:

    使用(StreamReader reader = new StreamReader(" C:\ ZyWall.log")) {   while((line = reader.ReadLine())!= null)    ...... }

  2. 每行阅读我都会根据其中的逗号将行拆分为多个部分。

    string [] lines = line.Split(new Char [] {','},10);

  3. 然后我遍历lines数组,为预定义的DataTable对象创建一个新Row,并为该行中的列分配数组值。然后我将行添加到数据表中。

  4. 在读取所有行到数据表之后,我使用OracleBulkCopy将数据写入数据库中具有相同结构的物理表。但问题是,当我向Datatable对象添加行时,我得到SystemOutOfMemoryException,这是第3步。如果我注释掉第3步然后在任务管理器中我看到应用程序消耗了大约17000 K的稳定内存量但是如果我取消注释该步骤,则内存使用量会增长,除非没有足够的内存来分配。还有一种方法可以使用BulkCopy来执行此操作,还是我必须手动执行此操作?我使用BulkCopy,因为它比逐个插入行更快。

1 个答案:

答案 0 :(得分:3)

如果我理解正确,您将在表格中加载每一行,以便达到系统内存的限制。
如果是这样,你应该找到这个限制。 (例如1000000行)。在此之前停止读取行,并使用OracleBulkCopy写入目前为止加载的行。清理你的记忆然后重新开始。所以让我用伪代码总结一切。

int lineLimit = GetConfiguration("lineLimit"); 
int lineNumber = 0;
DataTable logZyWall = CreateLogTable();

using(StreamReader reader=new StreamReader("C:\ZyWall.log")) 
{ 
    while ((line=reader.ReadLine())!=null)
    {
        DataRow row = ParseThisLine(line);
        logZyWall.Rows.Add(row);
        lineNumber++;
        if(lineNumber == lineLimit)
        {
            WriteWithOracleBulkCopy(logZyWall);
            logZyWall = CreateLogTable();
            lineNumber = 0;
        }
    }
    if(lineNumber != 0) WriteWithOracleBulkCopy(logZyWall);
}