【问题标题】:CSV string is being trimmed while importing with OleDb使用 OleDb 导入时正在修剪 CSV 字符串
【发布时间】:2018-07-04 15:47:15
【问题描述】:

我正在使用 oledb 机制读取 csv 文件。我的主要问题是读取时 csv 中的字符串值正在被修剪(两者:在开头和结尾处都有空格)。我在 csv 文件中有一些特定数据,仅在某些情况下需要有这样的空格 - 这就是为什么我在处理后无法处理的原因。必须通过转换来完成。

不幸的是,它必须使用 oledb 和 vb.net 来完成,因为我们的复杂机制基于这些技术。

是否有可能找到 oledb 不会修剪我的字符串的 hack 或解决方法?

以下是我的代码,实际结果和预期:

csv 文件:

Column1|Column2|Column3|Column4
Text1 | Text2| Text3 |Text4

schema.ini

[test.csv]
Format=Delimited(|)
Col1=Column1 Text
Col2=Column2 Text
Col3=Column3 Text
Col4=Column4 Text

代码

Private conn As New OleDbConnection
Private cmd As New OleDbCommand
Private myAccessDataReader As OleDb.OleDbDataReader = Nothing
Sub Main()

    Try
        Dim dirInfo As String = "C:\csv"

        If conn.State = ConnectionState.Open Then
            conn.Close()
        End If

        conn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & dirInfo & ";Extended Properties=""Text;HDR=Yes;"";"
        conn.Open()

        cmd = New OleDbCommand("SELECT * From [test.csv]", conn)

        myAccessDataReader = cmd.ExecuteReader()
        If myAccessDataReader.HasRows Then
            myAccessDataReader.Read()
        End If

        Console.WriteLine("|" + myAccessDataReader.Item("Column1") + "|")
        Console.WriteLine("|" + myAccessDataReader.Item("Column2") + "|")
        Console.WriteLine("|" + myAccessDataReader.Item("Column3") + "|")
        Console.WriteLine("|" + myAccessDataReader.Item("Column4") + "|")
        Console.ReadKey()

    Catch ex As Exception
        Throw New Exception(ex.Message)
    End Try


End Sub

实际结果:

|Text1|
|Text2|
|Text3|
|Text4|

预期结果:

|Text1 |
| Text2|
| Text3 |
|Text4|

附言。我在 schema.ini 中尝试过不同的设置:编码、MaxScanRows、固定宽度,但没有任何帮助。

【问题讨论】:

  • 我没有看到连接字符串中指定的格式:Extended Properties="text;HDR=YES;FMT=FixedLength"。然后,如您所知,您必须使用 schema.ini。 Text File Format, Schema.ini File.
  • @jimi 格式在模式文件中。
  • 如果您要读取整个文件并且不对其进行查询,那么我建议您将文件读取到数据表中。 OLE DB CSV 启用了 ansi 填充,但无法解决。
  • @brax 你完全破坏了 OP 的输出。

标签: vb.net csv oledb trim


【解决方案1】:

我想在处理数据库时尾随空格存在一个普遍问题:某些 char 数据类型使用空格来填充其余字符。对于 MSSql,有一个选项 ANSI PADDING,您可以打开/关闭它,但我看不到为我们用于 CSV 文件的 Microsoft JET Engine 设置它的方法;我们同时支持 oledb 和 odbc,并且两者都存在这个问题。

所以,答案是你不能。当您从 CSV 数据源导入数据时,始终会删除尾随空格,无论您是为列定义 text/char/memo 数据类型(例如使用 schema.ini)还是将字符串括在双引号中。您可以在最后放置一些特殊字符(非空格),在空格之后,例如制表符。

microsoft website

【讨论】:

    【解决方案2】:

    试试这个.....但不能保证,因为我没有进行任何错误处理......

    Function ReadCSVToTable(ByVal Schema As String) As DataTable
        Dim file As New StreamReader("C:\dump\" & Schema)
        Dim CSVName As String = file.ReadLine()
        CSVName = Strings.Mid(CSVName, 2, CSVName.Length - 2)
        Dim Delimiter As String = file.ReadLine
        Delimiter = Strings.Mid(Delimiter, Strings.InStr(Delimiter, "(") + 1, Delimiter.Length - Strings.InStr(Delimiter, ")") + 1)
        Dim Buffer As String = ""
        Dim xtable As New DataTable
        xtable.TableName = CSVName
        'create table
        Do
            Buffer = file.ReadLine
            Dim xCol As New DataColumn
            With xCol
                .ColumnName = Buffer.Split("=")(0)
                .Caption = Buffer.Split("=")(1).Split(" ")(0)
                Select Case Buffer.Split("=")(1).Split(" ")(1).ToLower
                    Case "text"
                        .DataType = GetType(String)
                    Case "integer"
                        .DataType = GetType(Integer)
                    Case "decimal"
                        .DataType = GetType(Decimal)
                    Case "boolean"
                        .DataType = GetType(Boolean)
                    Case Else
                        .DataType = GetType(String)
                End Select
            End With
            xtable.Columns.Add(xCol)
        Loop Until file.EndOfStream = True
        file.Close()
        file.Dispose()
    
    
        'Fill the table
        file = New StreamReader("C:\dump\" & CSVName)
        'skip header
        Buffer = file.ReadLine
        Do
            Buffer = file.ReadLine
            Dim xCol(xtable.Columns.Count - 1)
            Dim xCount As Integer = 0
            For Each tCol As DataColumn In xtable.Columns
                Select Case tCol.DataType
                    Case GetType(String)
                        xCol(xCount) = Convert.ToString(Buffer.Split(New String() {Delimiter}, StringSplitOptions.None)(xCount))
                    Case GetType(Integer)
                        xCol(xCount) = Convert.ToInt64(Buffer.Split(New String() {Delimiter}, StringSplitOptions.None)(xCount))
                    Case GetType(Decimal)
                        xCol(xCount) = Convert.ToDecimal(Buffer.Split(New String() {Delimiter}, StringSplitOptions.None)(xCount))
                    Case GetType(Boolean)
                        xCol(xCount) = Convert.ToBoolean(Buffer.Split(New String() {Delimiter}, StringSplitOptions.None)(xCount))
                    Case Else
                        xCol(xCount) = Convert.ToString(Buffer.Split(New String() {Delimiter}, StringSplitOptions.None)(xCount))
                End Select
                xCount = xCount + 1
            Next
            xtable.Rows.Add(xCol)
        Loop Until file.EndOfStream = True
        file.Close()
        file.Dispose()
        Return xtable
    End Function
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim CSVTable As DataTable = ReadCSVToTable("schema.ini")
    End Sub
    

    【讨论】:

    • 对不起,但我已经提到 oledb 连接是强制性的,因为它稍后在其他方法中用作参数。
    • @Arsey 玩得开心。我猜你还没有读过微软的帖子
    • @Arsey 我会留下代码,因为它可能对其他人有用。你不必投反对票。你可以留言代替
    • @Arsey 你知道如果你使用你的一些想象力并保存数据表来让我们说一个 MS 访问数据库并使用你的 ole 连接到访问数据库来传递给你的其他方法。我什至看不到在前面有空格的目的。我会理解你想把它们放在最后......
    猜你喜欢
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多