我们正在使用ZyWall来保护我们的服务器免受外部入侵。它生成每日日志文件,其大小超过GB,有时为2 GB。它们通常包含超过1000万行。现在我的任务是编写一个将这些行导入Oracle数据库的应用程序。我是用C#写的。我目前正在做的是:
我逐行阅读日志文件。我不会立即加载整个文件:
使用(StreamReader reader = new StreamReader(" C:\ ZyWall.log")) { while((line = reader.ReadLine())!= null) ...... }
每行阅读我都会根据其中的逗号将行拆分为多个部分。
string [] lines = line.Split(new Char [] {','},10);
然后我遍历lines数组,为预定义的DataTable对象创建一个新Row,并为该行中的列分配数组值。然后我将行添加到数据表中。
在读取所有行到数据表之后,我使用OracleBulkCopy将数据写入数据库中具有相同结构的物理表。但问题是,当我向Datatable对象添加行时,我得到SystemOutOfMemoryException,这是第3步。如果我注释掉第3步然后在任务管理器中我看到应用程序消耗了大约17000 K的稳定内存量但是如果我取消注释该步骤,则内存使用量会增长,除非没有足够的内存来分配。还有一种方法可以使用BulkCopy来执行此操作,还是我必须手动执行此操作?我使用BulkCopy,因为它比逐个插入行更快。
答案 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);
}