vb.net xls 到 csv 带引号?

Posted

技术标签:

【中文标题】vb.net xls 到 csv 带引号?【英文标题】:vb.net xls to csv with quotes? 【发布时间】:2011-03-09 18:50:27 【问题描述】:

我有一个 xls 文件,或一个不带引号的 csv,使用 vb.net 需要将其转换为每个单元格周围都有引号的 csv。如果我在 MS Access 中打开不带引号的 xls/csv,请将每一列设置为文本,然后将其导出为我需要的格式。有没有更简单的方法?如果没有,我如何在 vb.net 中复制它?谢谢。

【问题讨论】:

你能举一个数据的例子吗? "1","2","3","4" 是我需要的,而不是 1,2,3,4。 【参考方案1】:

如果您使用.Net OLE DB provider,您可以在您的数据文件所在文件夹中的 schema.ini 文件中指定 .csv 格式的详细信息。对于“未引用”的 .csv,请参阅规范 应该是这样的

[noquotes.csv]        <-- file name
ColNameHeader=True    <-- or False
CharacterSet=1252     <-- your encoding
Format=Delimited(,)   <-- 
TextDelimiter=        <-- important: no " in source file
Col1=VendorID Integer <-- your columns, of course
Col2=AccountNumber Char Width 15

对于“引用”的 .csv,只需更改名称并删除 TextDelimiter= 行(在文本字段周围加上引号是默认设置)。

然后连接到文本数据库并执行语句

SELECT * INTO [quotes.csv] FROM [noquotes.csv]

(因为这会创建quotes.csv,您可能希望在每次实验运行之前删除该文件)

新增处理“必须引用空字段”

这是一个 VBScript 演示,但重要的是 .GetString() 的参数,您可以轻松地将其移植到 VB:

    Dim sDir   : sDir       = resolvePath( "§LibDir§testdata\txt" )
    Dim sSrc   : sSrc       = "noquotes.csv"
    Dim sSQL   : sSQL       = "SELECT * FROM [" & sSrc & "]"
    Dim oTxtDb : Set oTxtDb = New cADBC.openDb( Array( "jettxt", sDir ) )
    WScript.Echo goFS.OpenTextFile( goFS.BuildPath( sDir, sSrc ) ).ReadAll()
    Dim sAll : sAll = oTxtDb.GetSelectFRO( sSQL ).GetString( _
                             adClipString, , """,""", """" & vbCrlf & """", "" _
                      )
    WScript.Echo   """" & Left( sAll, Len( sAll ) - 1 )

和输出:

    VendorID;AccountNumber;SomethingElse
    1;ABC 123 QQQ;1,2
    2;IJK 654 ZZZ;2,3
    3;;3,4

    "1","ABC 123 QQQ","1,2"
    "2","IJK 654 ZZZ","2,3"
    "3","","3,4"

(德语区域设置,因此字段分隔符;和十进制符号,)

此 VB.Net 代码的相同输出:

    Imports ADODB
    ...

        Sub useGetString()
            Console.WriteLine("useGetString")

            Const adClipString As Integer = 2
            Dim cn As New ADODB.Connection
            Dim rs As ADODB.Recordset
            Dim sAll As String

            cn.ConnectionString = _
                 "Provider=Microsoft.Jet.OLEDB.4.0;" _
               & "Data Source=M:\lib\kurs0705\testdata\txt\;" _
               & "Extended Properties=""text;"""

            cn.Open()
            rs = cn.Execute("SELECT * FROM [noquotes.csv]") 
            sAll = rs.GetString( adClipString, , """,""", """" & vbCrLf & """", "" )
            cn.Close()
            sAll = """" & Left( sAll, Len( sAll ) - 1 )
            Console.WriteLine( sAll )
        End Sub

【讨论】:

这听起来很棒,我会试试看。 是否可以在不指定每一列的情况下执行此操作?我想让它更通用,以便它能够转换任何 csv 文件。 如果您不指定列,驱动程序将猜测您想要(不)引用的类型和可能(不)引用字段。如果这是个问题,您可以在执行“SELECT INTO”语句之前以编程方式编辑 schema.ini 文件。 我不这么认为;我发现像“空字段可能用引号括起来”这样的语句,我的驱动程序没有这样做,而且我不记得为此目的的 schema.ini 属性。但这肯定不是结论性的。如果这对您的项目来说是致命的,并且您想引用所有字段,那么创造性地使用 ADO GetString 方法可能是一种无需循环即可进行转换的方法。 cADBC 是 ADODB.Connection 的包装类,oTxtDB 是该类(连接)的一个实例; goFS 是一个用于 IO 操作的 FileSystemObject; sALL 是将 .GetString 应用于记录集的结果。专注于 .GetString 的参数:字段分隔符设置为 '","',记录分隔符设置为 '"\r\n"'。然后我们只需要添加第一个“并切断虚假的最后一个”即可引用所有字段。【参考方案2】:

查看this link 的方法。 您可以做的是确保引号出现在将列数据放入文件的循环中,将引号附加到每个列数据的开头和结尾。

例如使循环如下:

For InnerCount = 0 To ColumnCount - 1
    Str &= """" & DS.Tables(0).Rows(OuterCount).Item(InnerCount) & ""","
Next

【讨论】:

那行得通。我想看看是否有任何其他解决方案,因为每次我不得不通过 vb.net 在 excel 文件中工作时,速度非常慢。 当我提出不同的解决方案时,我可能有偏见。但是考虑这种方法的人应该思考 3 个问题:您是否希望 (1) 引用所有字段值而不考虑类型? (2) 每行都有一个尾随? (3) 在具有不可变字符串的语言中使用 2. 级别循环中的字符串连接? @Ekkehard.Horner 这些都是非常值得思考的问题。【参考方案3】:
Public Class clsTest

Public Sub Test
Dim s as string = "C:\!Data\Test1.csv"

        Dim Contents As String = System.IO.File.ReadAllText(s)


        Dim aryLines As String() = Contents.Split(New String()  Environment.Newline , StringSplitOptions.None)
        Dim aryParts() As String
        Dim aryHeader() As String
        Dim dt As System.Data.DataTable 
        For i As Integer = 0 To aryLines.Length - 1
            aryParts = SplitCSVLine(aryLines(i))
            If dt Is Nothing And aryHeader Is Nothing Then 
                aryHeader = CType(aryParts.Clone, String())
            ElseIf dt Is Nothing And aryHeader IsNot Nothing Then
                dt = DTFromStringArray(aryParts, 1000, "", aryHeader)
            Else
                DTAddStringArray(dt, aryParts)
            End If
        Next
        dt.dump
End Sub 

Public Shared Function SplitCSVLine(strCSVQuotedLine As String) As String()
        Dim aryLines As String() = strCSVQuotedLine.Split(New String() Environment.NewLine, StringSplitOptions.None)
        Dim aryParts As String() = Nothing
        For i As Integer = 0 To aryLines.Length - 1
            Dim regx As New Text.RegularExpressions.Regex(",(?=(?:[^\""]*\""[^\""]*\"")*(?![^\""]*\""))")
            aryParts = regx.Split(aryLines(i))
            For p As Integer = 0 To aryParts.Length - 1
                aryParts(p) = aryParts(p).Trim(" "c, """"c)
            Next
        Next
        Return aryParts
End Function

Public Shared Function DTFromStringArray(ByVal aryValues() As String, Optional ByVal intDefaultColumnWidth As Integer = 255, Optional ByVal strTableName As String = "tblArray", Optional ByVal aryColumnNames() As String = Nothing) As DataTable
        If String.IsNullOrWhiteSpace(strTableName) Then strTableName = "tblArray"
        Dim dt As DataTable = New DataTable(strTableName)
        Dim colNew(aryValues.GetUpperBound(0)) As DataColumn
        If aryColumnNames Is Nothing Then
            ReDim aryColumnNames(aryValues.Length)
        Else
            If aryColumnNames.GetUpperBound(0) < aryValues.GetUpperBound(0) Then
                ReDim Preserve aryColumnNames(aryValues.Length)
            End If
        End If
        For x As Integer = aryColumnNames.GetLowerBound(0) To aryColumnNames.GetUpperBound(0)
            If String.IsNullOrWhiteSpace(aryColumnNames(x)) Then
                aryColumnNames(x) = "Field" & x.ToString
            Else
                aryColumnNames(x) = aryColumnNames(x)
            End If
        Next
        For i As Integer = 0 To aryValues.GetUpperBound(0)
            colNew(i) = New DataColumn
            With colNew(i)
                .ColumnName = aryColumnNames(i) '"Value " & i
                .DataType = GetType(String)
                .AllowDBNull = False
                .DefaultValue = ""
                .MaxLength = intDefaultColumnWidth
                .Unique = False
            End With
        Next
        dt.Columns.AddRange(colNew)
        Dim pRow As DataRow = dt.NewRow
        For i As Integer = aryValues.GetLowerBound(0) To aryValues.GetUpperBound(0)
            pRow.Item(i) = aryValues(i)
        Next
        dt.Rows.Add(pRow)
        Return dt
End Function

Public Shared Sub DTAddStringArray(ByRef dt As DataTable, ByVal aryRowValues() As String)
        Dim pRow As DataRow
        pRow = dt.NewRow
        For i As Integer = aryRowValues.GetLowerBound(0) To aryRowValues.GetUpperBound(0)
            pRow.Item(i) = aryRowValues(i)
        Next
        dt.Rows.Add(pRow)
End Sub

End Class

【讨论】:

考虑添加一个关于你在做什么以及它如何回答 OP 的问题的解释。

以上是关于vb.net xls 到 csv 带引号?的主要内容,如果未能解决你的问题,请参考以下文章

Liquibase CSV loadData 失败,带引号的字符串包含逗号

将 MySQL 导出为 CSV,一些列带引号,一些不带引号

Hive 在带引号的字段中使用逗号加载 CSV

正则表达式删除由双引号划定的 CSV 字段中的双引号

如何将数字转换为字符串

vb.net 怎么输出双引号,转