VB.NET 读取后释放 Excel 文件以便覆盖
VB.NET Releasing Excel file after reading so it can be overwritten
我遇到的问题和我之前的许多人遇到的问题一样,我发现了几个关于这个问题的话题,但我对他们的修复程序的应用没有产生任何变化。
我正在读取一个 excel 文件并用它填充 DataGridView。非常简单,用户可以修改它然后保存它。与其他线程一样,问题在于程序对文件的控制如此之紧,我无法覆盖它。
在提供的众多修复中,垃圾收集是最常提到的,但我的结果没有改变。我尝试处理 OLEDB 连接、命令、适配器和数据集也没有成功。
我已经 运行 通过几个不同的例子和教程来编写这个程序,所以如果需要这些修复,我显然在错误的地方实现了它们。
这是在表单加载时发生的阅读块(我已经删除了所有修复它以整理代码的尝试):
Private Sub Inventory_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Using MyConnection = New System.Data.OleDb.OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0;Data Source='c:\AllTrade\Inventory.xlsx';Extended Properties=Excel 8.0;")
Using MyCommand = New System.Data.OleDb.OleDbDataAdapter("select * from [InventorySheet$]", MyConnection)
DtSet = New System.Data.DataSet
MyCommand.Fill(DtSet)
InventoryGridView.DataSource = DtSet.Tables(0)
MyConnection.Close()
End Using
End Using
End Sub
这是保存块(这是生成 "File in Use" 错误的代码):
Private Sub UpdateInventory_Click(sender As Object, e As EventArgs) Handles UpdateInventory.Click
Dim ExcelApp As New Excel.Application()
ExcelApp.Application.Workbooks.Add(Type.Missing)
For i As Integer = 0 To InventoryGridView.Rows.Count - 1
Dim row As DataGridViewRow = InventoryGridView.Rows(i)
For j As Integer = 0 To row.Cells.Count - 1
ExcelApp.Cells(i + 1, j + 1) = row.Cells(j).Value
Next
Next
ExcelApp.ActiveWorkbook.SaveAs("C:\Alltrade\Inventory.xlsx")
ExcelApp.ActiveWorkbook.Saved = True
ExcelApp.Quit()
End Sub
释放文件有什么技巧?如果需要 GC.Collect()
和 GC.WaitForPendingFinalizers()
,它们会去哪里?
非常感谢您的帮助,并深表歉意,因为我无法成功实施来自类似主题的其他答案。
您需要编组以释放 COM 对象:ExcelApp...
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
Catch ex As Exception
MsgBox("Error releasing object" & ex.ToString)
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
您可以在子句末尾像这样调用此方法。
ReleaseObject(ExcelApp)
你可以在这里得到更多Excel application not quitting after calling quit
编辑
我还注意到您的连接字符串对于较新的 .xlxs 文件扩展名是错误的...
普通连接字符串:(适用于 xls 文件)
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=是;\""
Office 2007 连接字符串:(适用于 xlsx 文件)
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR=是;\""
经过大量研究和挫折,我找到了解决方案。
我的 OleDB 连接的连接字符串需要添加花絮:OLE DB Services = -4
禁用连接池。碰巧的是,当连接关闭时,连接并没有被释放(这是最初的假设),而是将连接转储回池中。
另一个论坛建议 OLE DB Services = -2
应该做同样的事情,但在我的实例中没有效果。它可能因版本而异,但我还没有对此进行研究以得出某些结论(或某个论坛中有人输入错误)
我的程序中不需要更多代码来转储 OleDB 连接对文件的保留。 MyConnection = Nothing
和排干水池的管道,然后是 GC.Collect
也被推荐,但没有解决我的症状。
感谢大家的意见
我遇到的问题和我之前的许多人遇到的问题一样,我发现了几个关于这个问题的话题,但我对他们的修复程序的应用没有产生任何变化。
我正在读取一个 excel 文件并用它填充 DataGridView。非常简单,用户可以修改它然后保存它。与其他线程一样,问题在于程序对文件的控制如此之紧,我无法覆盖它。
在提供的众多修复中,垃圾收集是最常提到的,但我的结果没有改变。我尝试处理 OLEDB 连接、命令、适配器和数据集也没有成功。
我已经 运行 通过几个不同的例子和教程来编写这个程序,所以如果需要这些修复,我显然在错误的地方实现了它们。
这是在表单加载时发生的阅读块(我已经删除了所有修复它以整理代码的尝试):
Private Sub Inventory_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Using MyConnection = New System.Data.OleDb.OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0;Data Source='c:\AllTrade\Inventory.xlsx';Extended Properties=Excel 8.0;")
Using MyCommand = New System.Data.OleDb.OleDbDataAdapter("select * from [InventorySheet$]", MyConnection)
DtSet = New System.Data.DataSet
MyCommand.Fill(DtSet)
InventoryGridView.DataSource = DtSet.Tables(0)
MyConnection.Close()
End Using
End Using
End Sub
这是保存块(这是生成 "File in Use" 错误的代码):
Private Sub UpdateInventory_Click(sender As Object, e As EventArgs) Handles UpdateInventory.Click
Dim ExcelApp As New Excel.Application()
ExcelApp.Application.Workbooks.Add(Type.Missing)
For i As Integer = 0 To InventoryGridView.Rows.Count - 1
Dim row As DataGridViewRow = InventoryGridView.Rows(i)
For j As Integer = 0 To row.Cells.Count - 1
ExcelApp.Cells(i + 1, j + 1) = row.Cells(j).Value
Next
Next
ExcelApp.ActiveWorkbook.SaveAs("C:\Alltrade\Inventory.xlsx")
ExcelApp.ActiveWorkbook.Saved = True
ExcelApp.Quit()
End Sub
释放文件有什么技巧?如果需要 GC.Collect()
和 GC.WaitForPendingFinalizers()
,它们会去哪里?
非常感谢您的帮助,并深表歉意,因为我无法成功实施来自类似主题的其他答案。
您需要编组以释放 COM 对象:ExcelApp...
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
Catch ex As Exception
MsgBox("Error releasing object" & ex.ToString)
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
您可以在子句末尾像这样调用此方法。
ReleaseObject(ExcelApp)
你可以在这里得到更多Excel application not quitting after calling quit
编辑
我还注意到您的连接字符串对于较新的 .xlxs 文件扩展名是错误的...
普通连接字符串:(适用于 xls 文件)
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=是;\""
Office 2007 连接字符串:(适用于 xlsx 文件)
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR=是;\""
经过大量研究和挫折,我找到了解决方案。
我的 OleDB 连接的连接字符串需要添加花絮:OLE DB Services = -4
禁用连接池。碰巧的是,当连接关闭时,连接并没有被释放(这是最初的假设),而是将连接转储回池中。
另一个论坛建议 OLE DB Services = -2
应该做同样的事情,但在我的实例中没有效果。它可能因版本而异,但我还没有对此进行研究以得出某些结论(或某个论坛中有人输入错误)
我的程序中不需要更多代码来转储 OleDB 连接对文件的保留。 MyConnection = Nothing
和排干水池的管道,然后是 GC.Collect
也被推荐,但没有解决我的症状。
感谢大家的意见