解决 C#、Java、VB、Delphi、VC 等语言中读写 Excel 文件太慢的问题

Posted by Admin L in .NET Programming, Common Programming on 08-04-2012. Tags:

作者:牧山道人
原文地址:https://www.seeksunslowly.com/operation-excel-xlsx-slowlw-sc
转载请注明出处,谢谢。
_____________________________________

最近,在 .NET 中尝试从 Excel 导入数据到 Detail 样式的 ListView 中,记录数在 3,000 左右,发现导入非常缓慢(将近 10 分钟),别说用户不能忍受,自己都无法接受,但这是必需的功能,不能去掉,所以必须想办法解决。

其中,读取 Excel 文档数据的方式为:逐行逐单元格读取,关键代码如下:

[cc lang=”vbnet”]
……
For r% = 1 To rows ‘ 外回圈,回圈于 rows,r = row。
For c% = 0 To 9 ‘ 内回圈,回圈于 columns,c = column。
fields(c) = sheet.Cells(r, c + 1).Text
Next
Next
……
[/cc]

通过在网上搜索,大部分说法是把 Excel 文件作为数据源,然后使用 ADO.NET 组件读取,这样会快很多。
这个方法我没去测试,因为这个解决方法也不能接受,整个软件没有一处用到数据库及相关组件,为了这个导入功能增加额外的组件,是我不能接受的,必须还得用 Excel 相关对象完成。

现在,只能自己摸索解决了,通过不断在 Excel 中录制宏,然后分析代码,发现了一种不用遍历所有单元格即可取得数据的方法。
感觉这个方法应该能大幅提高效率,因为除去与 Excel 应用、工作簿本身的交互,一个 sheet 我只需要访问一次就能取到所有数据。
经过测试,方法是可行的,效率是可观的。

其核心是 sheet.Range(“A1:X#”).Value 的使用。
sheet 对象的 Range 方法会返回指定区域所有数据:Object 类型的二维数组,第一维表示行,第二维表示列,各维下标都从 1 开始(Excel 内定的下标,跟其他一般编程语言不太一样)。
有了这个方法,一切变得如此简单,下面给出完整可用的 VB 2008 代码,细节(比如列数)请自行调整。
注意:这个方法不仅适用于 VB 2008,其他如 C#、Delphi、Java、VB、VC、PB 等语言同样适用(因为都可以通过对象操作 Excel)。

[cc lang=”vbnet”]
Private Sub ImportFromExcel(ByVal fn$)

‘ 从 Excel 文档读取数据,fn – Excel 档名。

On Error Resume Next

Dim excel As Object ‘ Excel application.
Dim wb As Object ‘ Excel workbook.
Dim sheet As Object ‘ Workbook sheet.
Dim rows% ‘ 当前 Sheet 有效行数。
Dim eData(,) As Object ‘ 用于撷取 Excel 资料。注意:必须为二维 Object 型别数组(各维下标均自 1 始)。

excel = CreateObject(“Excel.Application”)
If excel Is Nothing Then
MsgBox(“打开 Excel 应用失败,请确定您已正确安装 Excel。”, _
MsgBoxStyle.Exclamation)
Return
End If

wb = excel.Workbooks.Open(fn, , True) ‘ 唯读开启.

If wb Is Nothing Then GoTo CLS ‘ 未通过验证或用户取消(可能需要输入密码或出现其他对话框)。
sheet = wb.Worksheets(1)
rows = sheet.UsedRange.Rows.Count ‘ 取得当前 sheet 有效行数。

‘ 通过 sheet 对象的 Range 方法一次性读取整个 sheet 数据。
eData = sheet.Range(“A1:C” & rows.ToString).Value

” 以下代码简单打印读取到的数据。您需要将其转换为自己所开发产品的具体业务代码。
For i% = 1 To rows
For j% = 1 To 3
Debug.Print(eData(i, j)
Next
Next

CLS:
wb.Close() ‘ 关闭工作簿。
excel.Quit() ‘ 退出 Excel。

End Sub
[/cc]

最后,再补充一点,Range 方法也可用于 Excel 档案的写入。具体代码不再完整给出,核心部分如下:
[cc lang=”vbnet”]
Dim eData(1 To 100, 1 To 3) As Object ‘ 用于写入 Excel 资料。注意:必须为二维 Object 型别数组(各维下标均自 1 始)。
…… ‘ 准备好 eData
sheet.Range(“A1:C100”).Value = eData
…… ‘ 善后事宜。
[/cc]

【赞赏 / Reward】

微信         支付宝         PayPal

Post a comment