【问题标题】:How to query UTF-8 encoded CSV-files with VBA in Excel 2010?如何在 Excel 2010 中使用 VBA 查询 UTF-8 编码的 CSV 文件?
【发布时间】:2019-10-06 04:14:00
【问题描述】:

我想通过以下数据库连接在 Excel 2010 中使用 VBA 查询 UTF-8 编码的 CSV 文件:

provider=Microsoft.Jet.OLEDB.4.0;;data source='xyz';Extended Properties="text;HDR=Yes;FMT=Delimited(,);CharacterSet=65001"

所有 CSV 文件都以 BOM \xEF\xBB\xBF 和标题行开头。不知何故,BOM 没有被正确识别,第一列标题被读取为“?header_name”,即前面加上一个问号。我尝试过不同的字符集,也尝试过使用 Microsoft.ACE.OLEDB.12.0,但到目前为止一切都没有成功。

这是一个已知的错误,还是有什么方法可以在不更改源文件编码的情况下获得正确的第一列标题名称?

【问题讨论】:

  • 您介意分享您的 UTF-8 编码的 CSV 文件吗
  • @EEM 每个简单的 csv 文件,如 a,b,c\n 0.1,0.2,0.3\n 开头的 \xEF\xBB\xBF 都有同样的问题。
  • 1) 我很好奇只有​​ Microsoft.Jet.OLEDB.4.0 的原因和 2) Connection:="TEXT;Path & Filename" 根本不适用吗?

标签: excel vba csv utf-8 excel-2010


【解决方案1】:

以下过程将整个CSV文件提取到一个新的Sheet中,从标题中清除BOM。它具有路径、文件名和 BOM 字符串作为变量以提供灵活性。

使用此过程调用查询过程

Sub Qry_Csv_Utf8()
Const kFile As String = "UTF8 .csv"
Const kPath As String = "D:\StackOverFlow\Temp\"
Const kBOM As String = "\xEF\xBB\xBF"
    Call Ado_Qry_Csv(kPath, kFile, kBOM)
End Sub

这是查询过程

Sub Ado_Qry_Csv(sPath As String, sFile As String, sBOM As String)
Dim Wsh As Worksheet
Dim AdoConnect As ADODB.Connection
Dim AdoRcrdSet As ADODB.Recordset
Dim i As Integer

    Rem Add New Sheet - Select option required
    'With ThisWorkbook           'Use this if procedure is resident in workbook receiving csv data
    'With Workbooks(WbkName)     'Use this if procedure is not in workbook receiving csv data
    With ActiveWorkbook         'I used this for testing purposes
        Set Wsh = .Sheets.Add(After:=.Sheets(.Sheets.Count))
        'Wsh.Name = NewSheetName        'rename new Sheet
    End With

    Set AdoConnect = New ADODB.Connection
    AdoConnect.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
        "Data Source=" & sPath & ";" & _
        "Extended Properties='text;HDR=Yes;FMT=Delimited(,);CharacterSet=65001'"

    Set AdoRcrdSet = New ADODB.Recordset
    AdoRcrdSet.Open Source:="SELECT * FROM [" & sFile & "]", _
        ActiveConnection:=AdoConnect, _
        CursorType:=adOpenDynamic, _
        LockType:=adLockReadOnly, _
        Options:=adCmdText

    Rem Enter Csv Records in Worksheet
    For i = 0 To -1 + AdoRcrdSet.Fields.Count
        Wsh.Cells(1, 1 + i).Value = _
            WorksheetFunction.Substitute(AdoRcrdSet.Fields(i).Name, sBOM, "")
    Next
    Wsh.Cells(2, 1).CopyFromRecordset AdoRcrdSet

End Sub

【讨论】:

  • +1 CopyFromRecordset 很有可能!适用于逗号分隔的 csv 文件。我无法让它与分号分隔的文件一起使用,因为Delimited(;) 似乎除了逗号不接受任何其他内容。但由于 OP 使用逗号,所以没关系。
【解决方案2】:

我发现这个问题的唯一解决方案是使用Schema.ini 文件。

我的测试 csv 文件

Col_A;Col_B;Col_C
Some text example;123456789;3,14

用于我的测试 csv 文件的 Schema.ini

[UTF-8_Csv_With_BOM.csv] 
Format=Delimited(;)
Col1=Col_A Text
Col2=Col_B Long
Col3=Col_C Double

Schema.ini 文件包含源 csv 文件的名称并描述了我的列。每列由其名称和类型指定,但您可以指定更多信息。 此文件必须与您的 csv 文件位于同一文件夹中。更多信息here

最后是读取 csv 文件的 VBA 代码。请注意HDR=No。这是因为列标题是在Schema.ini 中定义的。

' Add reference to Microsoft ActiveX Data Objects 6.1 Library
Sub ReadCsv()

    Const filePath As String = "c:\Temp\StackOverflow\"
    Const fileName As String = "UTF-8_Csv_With_BOM.csv"
    Dim conn As ADODB.Connection
    Dim rs As New ADODB.Recordset

    Set conn = New ADODB.Connection
    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" & filePath & _
        "';Extended Properties='text;HDR=No;FMT=Delimited()';"

    With rs
        .ActiveConnection = conn
        .Open "SELECT * FROM [" & fileName & "]"
        If Not .BOF And Not .EOF Then
            While (Not .EOF)
                Debug.Print rs.Fields("Col_A") & " " & _
                            rs.Fields("Col_B") & " " & _
                            rs.Fields("Col_C")
                .MoveNext
            Wend
        End If
        .Close
    End With

    conn.Close
    Set conn = Nothing

End Sub

输出

Some text example 123456789 3,14

【讨论】:

  • 谢谢,我去看看。但是,我认为这意味着我必须以编程方式为我想要处理的每个不同的 csv 文件生成 schema.ini。
猜你喜欢
  • 1970-01-01
  • 2015-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多