填充数据表的.Net System.OutOfMemoryException

时间:2009-09-24 19:52:31

标签: .net vb.net dataset oledb dbf

我需要从.dbf文件中提取数据并将其转换为xml。我写了一个例程,它做得很好。但是现在我们遇到了非常大的.dbf文件 - 比如2GB +。此代码会对这些文件抛出OutOfMemoryException。

Public Function GetData() As DataTable
    Dim dt As New DataTable(Name)
    Dim sqlcommand As String= "Select * From MyTable"
    Dim cn As New OleDbConnection(myconnectionstring)

    Try
        cn.Open()
        Dim cmd As New OleDbCommand(sqlcommand, cn)
        dt.Load(cmd.ExecuteReader())
    Catch ex As Exception
        Throw ex
    Finally
        dt.Dispose()
        cn.Close()
        cn.Dispose()
    End Try
    Return dt

问题是 - 如果我在计算机上通过Visual Studio在调试模式下针对相同的2GB .dbf文件运行相同的代码,则不会抛出任何异常。它几乎就像Visual Studio管理内存的方式不同于应用程序单独执行内容。

有没有解决内存问题?我尝试过使用类似结果的DataAdapter。我在Visual Studio预期/设计中看到的这种行为是什么?

4 个答案:

答案 0 :(得分:6)

数据表在内存中,因此在大文件上会失败,或者根据文件的大小变慢。

您需要使用SqlDataReader按记录读取数据记录,并使用XmlWriter创建XML文件。

像这样(未检查代码)

Public Sub WriteToXml(Dim xmlFileName As String, Dim connectionString)
    Dim writer As XmlWriter
    writer = XmlWriter.Create(xmlFileName)
    Dim commandText As String= "Select * From MyTable"
    Dim connection As New OleDbConnection(connectionString)

    Try
        connection.Open()
        Dim command As New OleDbCommand(commandText, connection)
        Dim reader As SqlDataReader
        reader = myCommand.ExecuteReader()

        While reader.Read()             
            write.WriteRaw("xml")
        End While
    Catch ex As Exception
        Throw ex
    Finally        
        connection.Close()
        connection.Dispose()
    End Try
End Sub

答案 1 :(得分:4)

绝不可以在内存中加载整个2GB的数据库。您需要以块的形式加载和处理数据库记录

要进行部分加载数据库,可以使用SELECT命令中的TOP和ROWNUM子句。有关更多详细信息,请查看SQL Server的文档。

答案 2 :(得分:1)

如果要处理大文件,请考虑DataReader而不填充DataSet;它不会将整个表加载到内存中,而是逐行加载。并且还使用SqlDataAdapter.Fill()而不是这种方式,不要忘记Dispose it。

Dim conn As New SqlConnection(connection)
Dim adapter As New SqlDataAdapter()
adapter.SelectCommand = new SqlCommand(query, conn)
adapter.Fill(dataset)
adapter.Dispose()
conn.Dispose()

您实际上不需要调用.Close()来进行连接,因为在调用.Dispose()时会调用它。

PS:你没有关闭Reader,这可能就是原因。是的,VS.NET将比GC更快地关闭它。

答案 3 :(得分:1)

为什么不做一些简单的事情:

using (var writer = CreateXmlWriter(fileName))
{
  while (reader.Read()) 
  {
    var value = new ObjectFromDatabaseReader(reader);
    value.WriteXml(writer);
  }
}

这将只是一次一行地传输数据,转换为对象然后保存为xml。这根本不会使用任何内存,应该非常快。