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

4 回答 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
于 2009-09-24T20:10:49.807 回答
4

您绝对不能在内存中加载整个 2GB 的数据库。您将需要分块加载和处理数据库记录

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

于 2009-09-24T20:00:14.467 回答
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() 时被调用。

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

于 2009-09-24T20:00:10.863 回答
1

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

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

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

于 2009-09-24T22:18:48.037 回答