【问题标题】:importing CSVs into Excel将 CSV 导入 Excel
【发布时间】:2012-08-06 04:10:19
【问题描述】:

我需要将一些 CSV 导入 Excel 电子表格,每个 CSV 的行/列数都不同。问题是某些值是长数字字符串,例如
341235387313289173719237217391,

Excel 会将这些值视为(双)数字,然后导致数据丢失。

我解决它的方法是使用以下function 来完成这项工作:

Sub readCSV(f As TextStream, sh As Worksheet)
    i = 1
    Do
        l = Trim(f.ReadLine)
        If l = "" Then Exit Sub 'skip the last empty line(s)
        l = Mid(l, 2, Len(l) - 1)
        ss = Split(l, """,""")
        For j = LBound(ss) To UBound(ss) 'j starts from 0
            Dim a As Range
            With sh.Cells(i, j + 1)
                .NumberFormat = "@" 'Force to text format
                .Value = ss(j)
            End With
            DoEvents 'Avoid blocking the GUI
        Next j
        i = i + 1
    Loop Until f.AtEndOfStream
End Sub

问题在于性能。它比通过 Data->From Text 导入数据或直接打开 CSV 慢得多。

有什么方法可以提高效率吗?

【问题讨论】:

  • 尝试关闭屏幕更新并将计算设置为手动(不要忘记在最后重新打开它)。并尝试注释掉您的 DoEvents 调用。
  • 最初我没有使用 DoEvents 调用,但是它仍然比直接加载慢得多。我必须使用它,因为我不能等待太久而不知道发生了什么。

标签: vba excel vba csv data-import


【解决方案1】:

您可以一次格式化/写入每一行:

Sub readCSV(f As TextStream, sh As Worksheet)

     Dim i As Long
     Dim ss, l
     i = 1

    With Application
        .ScreenUpdating = False
        .Calculation = xlCalculationManual
    End With

    Do
        l = Trim(f.ReadLine)
        If l = "" Then Exit Sub 'skip the last empty line(s)
        l = Mid(l, 2, Len(l) - 1)
        ss = Split(l, """,""")

        With sh.Cells(i, 1).Resize(1, (UBound(ss) - LBound(ss)) + 1)
            If (i-1) Mod 100 = 0 Then .Resize(100).NumberFormat = "@"
            .Value = ss
        End With

        i = i + 1
    Loop Until f.AtEndOfStream

    With Application
        .ScreenUpdating = True
        .Calculation = xlCalculationAutomatic
    End With


End Sub

编辑:经过测试,真正的性能杀手是将单元格格式设置为文本修改代码,以 100 行而不是每行的块进行设置。

【讨论】:

  • 我同意您一次一行的做法,但我建议您跳过调整大小的步骤,如下所示:With sh.Range(sh.Cells(i, 1),sh.Cells(i,UBound(ss))
  • 这看起来很棒,实际上速度非常快!谢谢你。我会将此标记为答案
  • 为了减少格式设置,我会建议sh.Cells.NumberFormat="@"
【解决方案2】:

您可以使用 Regexp 快速创建 CSV 文件的第二个版本,而不是在 Excel 中工作(按单元格或按行),其中每个长度超过 16 个字符的字母数字字符串都使用前面的 ' 进行更新

然后只需在 Excel 中导入或打开整个新的 csv

在 CSV 文件 StrIn 上运行的示例代码,此路径为示例,"c:\Temp\test.csv"

Sub Main()
Dim objFSO As Object
Dim objRegex As Object
Dim objTF As Object
Dim objTF2 As Object
Dim tf As Object
Dim strIn As String
Dim strOut As String
Dim strFile As String

strIn = "c:\Temp\test.csv"
strOut = "c:\Temp\test2.csv"

Set objFSO = CreateObject("scripting.filesystemobject")
Set objTF = objFSO.getfile(strIn)
Set objRegex = CreateObject("vbscript.regexp")
Set tf = objTF.OpenAsTextStream(ForReading)
strFile = tf.ReadAll

With objRegex
.Pattern = "(\w{16,})"
.Global = True
strFile = .Replace(strFile, "'" & "$1")
End With

Set objTF2 = objFSO.OpenTextFile(strOut, ForWriting, True)
objTF2.Write strFile
objTF2.Close
tf.Close
End Sub

【讨论】:

  • @EarthEngine - 你看到了吗? :)
  • 虽然我相信这是一个好方法,但恐怕给定的正则表达式可能不起作用。我的一些数据值是长语句,例如“某人有一个名字来破解程序的编号是 232313435345423423”等等,所以不能用“某人有一个名字来破解程序的编号是 '232313435345423423”甚至“某人有一个名字来破解程序的编号是 '2323134” .
  • @EarthEngine 感谢您的澄清。这可以通过更改正则表达式模式来处理,但我会留下它,就好像你对你的答案很满意
【解决方案3】:

试试.Value = "'" & ss(j)

' 强制值在 Excel 中显示为文本字符串。

另外,尝试在字符串中声明你的 ss 数组,这样它就不会在拆分后将数字存储为 long。比如:

Dim ss() as String = Split(l, """,""")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-27
    • 2012-10-09
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多