代码之家  ›  专栏  ›  技术社区  ›  brendan

.NET System.OutOfMemoryException填充数据表

  •  3
  • brendan  · 技术社区  · 15 年前

    我需要从.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管理内存的方式与应用程序单独管理内存的方式不同。

    有没有办法解决内存问题?我尝试使用具有类似结果的数据适配器。我在Visual Studio中看到的这种行为是预期的还是按设计的?

    4 回复  |  直到 15 年前
        1
  •  6
  •   Ehz    15 年前

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

    您需要使用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
    
        2
  •  4
  •   Konamiman    15 年前

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

    要部分加载数据库,可以使用select命令中的top和rownum子句。有关详细信息,请参阅SQL Server的文档。

        3
  •  1
  •   Vitaly    15 年前

    如果要处理大型文件,请考虑不填充数据集的DataReader;它不会在内存中加载整个表,而是逐行加载。也可以使用sqldataadapter.fill()来代替这种方法,不要忘记释放它。

    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()时会调用它。

    附言:你不能关闭读者,可能这就是原因。是的,vs.net将比GC更快地关闭它。

        4
  •  1
  •   Nick Randell    15 年前

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

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

    这将一次以一行的形式传输数据,转换为对象,然后另存为XML。这将几乎不用任何内存,而且应该非常快。