【问题标题】:Very large excel file - how to copy data between sheets?非常大的ex​​cel文件 - 如何在工作表之间复制数据?
【发布时间】:2012-09-17 20:41:51
【问题描述】:

我需要将一些 csv 文件导入 excel 2010 并创建一个非常简单但非常大的数据库。
整个故事将是 - 五列和数千行。
VBA 也很简单 - 将数据从一张表复制到另一张表 - 反之亦然。
但我需要关心内存需求,因为文件可能非常大。

Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim r1 As Range
Dim r2 As Range
Set ws1 = Sheets("01")
Set ws2 = Sheets("02")
Set r1 = ws1.Range("A1:B10") ' for example
Set r2 = ws2.Range("C5:D14")
r1.Copy Destination:=r2 'first way
r2.Value = r1.Value ' second way

这两种方法在内存/耗时范围内有什么区别吗?
在和我将有超过 10,000 行。文件的大小是多少?

【问题讨论】:

  • Is there any differences between this two methods, in the scope of memory/time consuming? 试试看!尝试!尝试!在您的代码中放置一个计时器并相互测试您的方法。 What will be the size of the file? 与上述相同的答案。不看数据集就无法判断。
  • Instant - 取决于你对这个词的定义。对于您在 Excel 中的行大小,我怀疑您是否会找到符合您定义的任何内容。我在下面发布了一些用于 CSV 导入的代码,这些代码可能比打开 csv 并将数据从工作簿复制到工作簿更有效。如果没有帮助,请告诉我。我将作为“答案”删除。

标签: excel vba


【解决方案1】:

您可以利用 ADO 来查询文本文件,就好像它们是数据库表一样。这允许您编写 SQL 查询以从文本文件中提取数据。如果您愿意,您可以在任何文本文件甚至 .xls 文件中执行此操作。

这样做的代码/过程相当简单。您需要先引用 Microsoft ActiveX Data Objects 2.X Library,然后使用类似以下内容:

Dim cn as New ADODB.Connection
Dim rs as New ADODB.Recordset
Dim i as Integer

With cn
    .Provider = "Microsoft.Jet.OLEDB.4.0"
    .ConnectionString = "Data Source=C:\SomeFolder;" & _
                        "Extended Properties=""text; HDR=Yes;FMT=Delimited"""
    .Open

    With rs
        .Open "SELECT * from fileName.txt", cn

        'Loop through each row in query
        While Not (.EOF Or .BOF)
            'Loop through each column in row
            For i = 0 to .Fields.Count - 1
                Debug.Print .Fields(i).Value 'Print value of field to Immediate Window
            Next i

            .MoveNext
        Wend

        .Close
    End With

    .Close
End With

Set rs = Nothing
Set cn = Nothing

这将遍历您的文本文件并在您的 VBA 即时窗口中显示第一列的值。它还假定您的文件具有标题行。如果没有,那么您需要将 ConnectionString 中的 HDR 更改为 No

代码会自动尝试并为您推断类型,但如果您遇到了无法发现正确类型(例如前导零)的问题,那么您可以为您的文件显式定义架构。请务必注意,如果您采用架构路由,那么您的 ConnectionString 参数(如 HDRFMT 将被忽略)。它们将保留注册表中定义的默认设置,除非您在架构定义中覆盖它们。有关 schema.ini 文件的更多信息可以在这里找到:http://msdn.microsoft.com/en-us/library/windows/desktop/ms709353(v=vs.85).aspx

这是另一个有用的链接:http://msdn.microsoft.com/en-us/library/ms974559.aspx。这是一篇由 Microsoft Scripting Guys 撰写的文章,也是我最初了解该过程的方式。

最后,如果您曾经对 .xls 文件使用此过程,那么您应该知道永远不要查询打开的 .xls 文件。 OPEN .xls 文件存在严重的内存泄漏错误(更多信息:http://support.microsoft.com/default.aspx?scid=kb;en-us;319998&Product=xlw)。只要您查询 CLOSED .xls 文档,那么您就不应该有任何问题 =D。 SQL FROM 子句中的语法有点不同,因为您必须针对特定工作表,但 IIRC 我链接的 Scripting Guys 文章解释了如何做到这一点。

【讨论】:

  • Kittoes,非常感谢您的努力,尤其是您的解释。我需要研究这种方法。
  • @Alegro NP。将文本文件中的任何数据导入 Excel(或 Access)时,我更喜欢这种方法,因为它快速且极其灵活。我也喜欢它,因为它遵循与从实际数据库中提取数据几乎相同的逻辑/语法。如果我从 SQL Server 查询数据,那么我唯一需要更改的就是 SELECT 语句和 Provider/Driver/Connection 字符串。仅通过一个简单的 WHERE 子句来限制导入内容的能力也非常棒。
  • Kittoes,我喜欢通用解决方案。我现在明白了,你的代码真的很珍贵。多谢。再一次:谢谢伙计。
  • @Alegro 大声笑,只是向前支付。当我看到那个 MSDN 文章时,我真的大声说“没门”。您可以轻松地将它与所有东西一起使用,这真是太疯狂了。请记住,像我上面所做的那样遍历记录并不是您处理查询返回的数据的唯一方法。您可以真正发挥您的想象力,找出最适合特定项目的方法。理论上,您甚至可以最终将数据放入 Excel 表格中,类似于 Scott 上面所做的。
【解决方案2】:

这个代码块有一些我参与的项目的细节,但应该可以帮助你开始如何通过 VBA 导入 CSV 文件(有点清理):

Public Sub ImportCSV(strPath As String, strFile As String, strExt As String, wbDestination As Workbook, Optional wsDest As Worksheet, Optional strRange As String, Optional blHeaders As Boolean = True)
'imports given CSV file into given sheet at given range _
    defaults to comma separated delimiters

Dim wsDestination As Worksheet
Dim strFileName As String
strFileName = strPath & strFile & ".csv"


If wsDest Is Nothing Then Set wsDestination = wbDestination.Worksheets.Add(, wbDestination.Worksheets(wbDestination.Worksheets.Count)) Else: Set wsDestination = wsDest
If strRange = "" Then strRange = "$A$1"

With wsDestination.QueryTables.Add(Connection:="TEXT;" & strFileName, Destination:=wsDestination.Range(strRange))
        .FieldNames = False
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        .SaveData = False
        .AdjustColumnWidth = False
        .RefreshPeriod = 0
        .TextFilePromptOnRefresh = False
        .TextFilePlatform = 437
        .TextFileStartRow = 1
        .TextFileParseType = xlDelimited
        .TextFileTextQualifier = xlTextQualifierDoubleQuote
        .TextFileConsecutiveDelimiter = False
        .TextFileTabDelimiter = False
        .TextFileSemicolonDelimiter = False
        .TextFileCommaDelimiter = True
        .TextFileSpaceDelimiter = False
        .TextFileTrailingMinusNumbers = True
        .Refresh BackgroundQuery:=False
        .Delete
    End With

If Not blHeaders Then wsDestination.Range(strRange).EntireRow.Delete

End Sub

【讨论】:

  • 斯科特,这不仅仅是一个答案。此外,我在阅读您的代码时收到了一些额外的想法。非常感谢。
猜你喜欢
  • 2015-09-17
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多