【问题标题】:How to keep leading zeros when opening CSV file in VBA在 VBA 中打开 CSV 文件时如何保持前导零
【发布时间】:2021-03-13 08:39:39
【问题描述】:

我有一个 VBA 代码可以快速从 CSV 文件传输数据,但不幸的是排除了前导零(例如 000123 转换为 123)

Filename = "c:\text.csv"
Dim wbI As Workbook, wbO As Workbook
Dim wsI As Worksheet
Set wbI = ThisWorkbook
Set wsI = wbI.Sheets("Temp")
Filename = "c:\text.csv"

Set wbO = Workbooks.Open(Filename) 
wbO.Sheets(1).Cells.Copy wsI.Cells
wbO.Close SaveChanges:=False

我尝试打开csv文件后添加以下内容> Cells.NumberFormat = "@"

Set wbO = Workbooks.Open(Filename) 
Cells.NumberFormat = "@"
wbO.Sheets(1).Cells.Copy wsI.Cells
wbO.Close SaveChanges:=False

不幸的是,它不起作用,我看到的问题是文件打开后已经缺少前导零

是否可以在不影响前导零的情况下打开文件并将所有数据显示为文本以保持前导零?

【问题讨论】:

  • 你知道csv文件有多少列吗?它是否始终具有相同数量的列?是TabDelimited 类型的吗?
  • 它是逗号分隔的。它有29列,列数不会改变

标签: vba csv


【解决方案1】:

请试试这个方法:

Sub testOpenWithLZeroTxt()
 Dim Filename As String, wbI As Workbook, wbO As Workbook, wsI As Worksheet
 Dim arrTXT, nrCol As Long, arr(), i As Long, sep As String, lineSep As String
 Dim allTxt As String, txtStr As Object, fileTxt As String, fs As Object, f As Object, ts As Object
 
 Set wbI = ThisWorkbook
 Set wsI = wbI.Sheets("Temp")
 Filename = "c:\text.csv"
    fileTxt = Split(Filename, ".")(0) & ".txt" 'create a helper txt file using the csv string content
    
    Set fs = CreateObject("Scripting.FileSystemObject")
    allTxt = fs.OpenTextFile(Filename, 1).ReadAll 'reed the csv file content
    fs.CreateTextFile fileTxt
    Set f = fs.GetFile(fileTxt)
    Set ts = f.OpenAsTextStream(2, -2)
        ts.write allTxt                          'write the csv content in a newly created txt file
    ts.Close
    
    'Check the number of text file columns:_______
    sep = vbLf ' if not working you can try vbCrLf. It works so on your file
    lineSep = ","  'it my be vbTab, ";" etc. It works so on your file
    arrTXT = Split(allTxt, sep)
    nrCol = UBound(Split(arrTXT(0), lineSep))
    '_____________________________________________
    
    ReDim arr(nrCol) 'redim the format array
    For i = 0 To nrCol
        arr(i) = Array(i + 1, 2) 'fill the format array with variant for TEXT Format!
    Next
    'open the helper txt file as you need:
    Workbooks.OpenText Filename:=fileTxt, origin:=437, startRow:=1, _
                DataType:=xlDelimited, Tab:=False, Comma:=True, FieldInfo:=arr()
    Set wbO = ActiveWorkbook
    'wbO.Sheets(1).cells.Copy wsI.Range("A1") 'copy the content
    wbO.Close SaveChanges:=False              'close the file
    Kill fileTxt                              'kill helper txt file
End Sub

已编辑

我改变了代码理念。它将首先读取字符串变量中的 csv 内容,并使用获得的字符串创建一个 txt 文件并将其作为文本打开,这当然应该可以工作。它适用于 csv 文件中的任意数量的列。

【讨论】:

  • 抱歉,没用。它仍被复制为数字,前导零消失。如果我停止打开 csv 文件的过程,我已经可以看到源文件中缺少前导零。前导零肯定存在,就像我用记事本打开文件一样,我可以看到它们。
  • @Selrac:这可能只是因为你没有告诉我哪个是分隔符以及行尾分隔符......它是CSV逗号分隔类型吗?上面的代码,正如我所说的,适用于这种类型。如果不起作用,请将sep 变量从vbLf 更改为vbCrLf... 有两个专用变量可以更改上述分隔符:seplineSep
  • 以逗号分隔(如 1131905040,00384289275004753375)。我尝试更改为 sep = vbCrLf 但没有任何影响
  • @Selrac:如果不是机密,你能在讨论中分享 csv 文件吗?如果是,您可以使用this 转移站点。它是免费且易于使用的......同时,请测试改编的代码,不再计算列数。它适用于 29 列。
  • @Selrac:我做了一些简短的测试,文件确实是逗号分隔的,vbLf 就像行分隔符一样工作。我不明白为什么它没有作为文本打开,但现在没有时间检查更多。我必须在几分钟后离开家,我把你的问题当作挑战。我将修改代码以读取 csv 内容,将其放入文本文件中,然后根据需要打开它。最后,帮助文件将被删除。当我有足够的时间调查时,我会更深入地研究它......
【解决方案2】:

您的 csv 文件中的换行符是 unix LF。这对应于 chr(10)。

由于第一行的列数和下一行的列数不一致,所以使用了一点偏差。通过将第一行的列数加倍来创建一个数组。

Sub test()
    Dim Ws As Worksheet
    Dim Fn As String
    Dim Arr As Variant
    
    Fn = "Example.csv"
    'Fn = "c:\text.csv"
    Set Ws = Sheets("Temp")
    
    Arr = getDatFromCsv(Fn)
    
    With Ws
        .Cells.NumberFormat = "@"
        .Cells = Empty
        .Range("a1").Resize(UBound(Arr, 1) + 1, UBound(Arr, 2) + 1) = Arr
    End With
    
    
End Sub
Function getDatFromCsv(strFn As String) As Variant
    Dim vR() As String
    Dim i As Long, r As Long, j As Integer, c As Integer
    Dim objStream  As Object
    Dim strRead As String
    Dim vSplit, vRow
    Dim s As String
    
    Set objStream = CreateObject("ADODB.Stream")

    With objStream
        .Charset = "utf-8"
        .Open
        .LoadFromFile strFn
         strRead = .ReadText
        .Close
    End With
    
    vSplit = Split(strRead, Chr(10)) 'Unix Lf ~~> chr(10)
    r = UBound(vSplit)
    c = UBound(Split(vSplit(0), ",", , vbTextCompare))
    ReDim vR(0 To r, 0 To c * 2)
    
    For i = 0 To r
        vRow = Split(vSplit(i), ",", , vbTextCompare)
        'If UBound(vRow) = c Then 'if it is empty line, skip it
            
            For j = 0 To UBound(vRow)
                vR(i, j) = vRow(j)
            Next j
        'End If
    Next i
    getDatFromCsv = vR
    
    Set objStream = Nothing

End Function

结果图片

【讨论】:

  • 代码在这一行失败:".Range("a1").Resize(UBound(Arr, 1) + 1, UBound(Arr, 2) + 1) = Arr" 出现错误'运行时错误 1004 应用程序定义或对象定义错误"
  • 成功了,谢谢!!我不明白你的代码到底在做什么,但它很棒。
【解决方案3】:

请改用OpenText method

最重要的参数是FieldInfo。你需要通过:

包含单个数据列的解析信息的数组。解释取决于 DataType 的值。当数据被分隔时,这个参数是一个二元素数组的数组,每个二元素数组指定特定列的转换选项。第一个元素是列号(从 1 开始),第二个元素是 XlColumnDataType 常量之一,指定如何解析列

换句话说,每列前导零,都必须定义为xlTextFormat

我建议录制宏。 ;) 加载文本数据的选项,您可以在Data 选项卡下找到 -> ... -> From text/CSV

【讨论】:

  • 我尝试使用 OpenText 和 fileInfo,但无法正常工作
  • 从@FaneDuru 的回答中我可以看出你是对的。 FaneDuru 解决方案很有用,因为它可以识别列数,以便创建一个数组来定义 FieldInfo 格式为 (n,2) 的所有列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-26
  • 2023-01-28
  • 2017-05-17
  • 1970-01-01
相关资源
最近更新 更多