使用.NET时填充数据表时出现OutOfMemoryException异常

3
我需要从一个.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个回答

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

4

无论如何,您都不能在内存中加载整个2GB的数据库。您需要分块加载和处理数据库记录。

为了实现数据库的部分加载,您可以使用例如SELECT命令中的TOP和ROWNUM子句。有关更多详细信息,请查看SQL Server的文档。


1
为什么不做一些简单的事情,比如:
using (var writer = CreateXmlWriter(fileName))
{
  while (reader.Read()) 
  {
    var value = new ObjectFromDatabaseReader(reader);
    value.WriteXml(writer);
  }
}

这将一次只以一行的方式流式传输数据,转换为对象,然后保存为xml。这几乎不会占用任何内存,并且应该非常快。


1
如果你想处理大文件,考虑使用DataReader而不是填充DataSet;它不会将整个表加载到内存中,而是逐行进行。并且使用SqlDataAdapter.Fill()而不是这种方式,别忘了Dispose它。
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() 时它会自动关闭。

另外,你没有关闭 Reader,可能是这个原因。是的,VS.NET 会比 GC 更快地关闭它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接