【问题标题】:CSV to DataTable parsing float values as DateCSV 到 DataTable 将浮点值解析为日期
【发布时间】:2021-01-05 16:20:46
【问题描述】:

我正在尝试将 CSV 解析为 VB.NET 项目中的 DataTable,问题是当我导入 CSV 文件时,值像 ;2,08;2;0,82 这样浮动的列被导入为 30/12/1899 02:08:0030/12/1899 02:00:00

如何防止 oledb 格式化数据?

这是我将 csv 加载到数据表的方式:

        Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & path & ";Extended Properties=""text;HDR=YES;FMT=Delimited(;)""")

        con.Open()
        Dim da As New OleDbDataAdapter(sqlquery, con)
        da.Fill(dt)

在 CSV 所在的同一文件夹中,我有 schema.ini,其内容如下:

[anar_adm.csv]
Format=Delimited(;)

【问题讨论】:

  • 使用逗号作为小数分隔符的文化是什么?我想我有一个解决方案给你,但我想先测试一下。我猜是意大利,因为那是你来自的地方:)
  • @MarkPflug 嗨,马克,是的,你是对的,它是意大利语 :)

标签: vb.net csv oledb


【解决方案1】:

我维护了一个可以处理这种情况的库:Sylvan.Data.Csv

这是我为验证它是否按预期工作而编写的代码。抱歉,这是用 C# 编写的,因为我不太了解 VB,所以应该很容易翻译。

using var reader = new StringReader("Name;Value1;Value2\nTest;2,08;0,82\n");

var schema = Schema.Parse("Name,Value1:float,Value2:float");

var options = new CsvDataReaderOptions {
    Schema = new CsvSchema(schema),
    // you would likely replace this with CurrentCulture
    // the default is InvariantCulture
    Culture = CultureInfo.GetCultureInfoByIetfLanguageTag("it-IT")
};
var csv = CsvDataReader.Create(reader, options);
var dt = new DataTable();
dt.Load(csv);

CsvDataReader 来自Sylvan.Data.CsvSchema.Parse 行来自Sylvan.Data,这是预发布的。您不必使用Schema.Parse,而是可以提供自己的ICsvSchemaProvider。在这个Answer 中有一个简单模式提供程序的示例。

与 OleDB 相比,它的优势在于它是完全托管的,不需要外部驱动程序,也不需要 schema.ini。它也是much, much faster,如果性能是一个问题(事实上,它对于.NET 来说是最快的)。缺点是您需要自己提供架构,而 OleDB 会尝试从数据中自动检测它(有时会出错)。

【讨论】:

    【解决方案2】:

    Schema.ini 文件有不同的选项,您可以在这里阅读。
    Schema.ini File (Text File Driver)

    除其他外,您可以指定列数据类型以及小数点分隔符。例如,定义 4 列的架构,其中:

    • ColNameHeader=True:数据文件包含列定义
    • Format=Delimited(;):列之间用分号隔开
    • DecimalSymbol=,:小数点分隔符是逗号
    • Col(N)=ColumnName TYPE [WIDTH] [#]:列的名称和类型,以及(可选)列的宽度。宽度值 ([#]) 是必需的。

    如果列可能包含不是系统默认值的货币符号,请指定货币格式。例如,使用 Euro 符号:

    • CurrencySymbol=[Symbol]:数据文件中使用的货币符号。

    • CurrencyPosFormat=[N]:正值的符号位置。这可以是以下 4 个值之一:
      0 = €1,1 1 = 1,1€ 2 = € 1,1 3 = 1,1 €

    • CurrencyNegFormat=[N]:同上,但可以指定更多位置。有关可能值的列表,请参阅之前链接的文档

    • CurrencyDigits=[N]:货币使用的小数位数

    • CurrencyThousandSymbol=[Symbol]:千位分隔符

    • CurrencyDecimalSymbol=[Symbol]:小数分隔符

    CharacterSet 指定 CSV 文件使用的编码方式。标准值为:

    • ANSI(本地代码页)、OEMUnicode。其他编码必须使用它们的 CodePage 来指定。例如,UTF-8 需要指定为 CodePage 65001
      系统中所有可用的代码页都列在此注册表项中:
      HKEY_CLASSES_ROOT\MIME\Database\Charset

    使用此 CSV 内容:

    ID;Description;Quantity;FloatValue;Price
    1;String 1;100;10,56;€10,79
    2;String 2;101;12,72;€200,34
    3;String 3;33;100657,72;€0,98
    

    Schema.ini 文件可以如下:

    [filename.csv]
    ColNameHeader=True                First row is the Columns Header
    MaxScanRows=0                     No auto-detect Column Type
    CharacterSet=65001                UTF-8 file Format
    Format=Delimited(;)               Columns delimiter
    DecimalSymbol=,                   Decimals separator
    NumberLeadingZeros=1              Below 1 values leading zeros (0,12)
    CurrencySymbol=€                  Currency symbol (if present)
    CurrencyPosFormat=0               Currency positive format: €1,1
    CurrencyNegFormat=1               Currency negative format: -€1,1
    CurrencyDigits=2                  Number of Decimal digits
    CurrencyThousandSymbol=.          Thousands separator
    CurrencyDecimalSymbol=,           Decimal separator
    Col1=ID Long                      |-- Columns definition
    Col2=Description Text WIDTH 50    |
    Col3=Quantity Integer             |
    Col4=FloatValue Double            |
    Col5=Price Currency               |
    
    [otherFilename.csv]
    ColNameHeader=True
    MaxScanRows=25                   | Auto-detect the data type, using 25 rows as sample
    CharacterSet=ANSI
    Format=Delimited()               | Standard delimiter: (,)
    

    无论如何,我建议以CsvHelper 的形式获取库

    【讨论】:

    • 这并不能解决我的问题,应该是双倍的值仍然是日期,我实际上是通过使用following 问题的答案解决的,但我仍然会等待 OleDB 解决方案..我也会通过在 .ini 中设置列​​数据类型来避免,因为它会为其他 csv 改变
    • 这是 CSV 格式的标准 Schema.iniDecimalSymbol 是一个转换说明符,当 Column 的数据类型一致且应用正确时,它始终有效(顺便说一句,我刚刚使用相同的 Provider 对其进行了测试)。没有 OleDb 解决方案,如您所见,Schema.ini 与特定的 CSV 文件相关。如果您对此有疑问,请获取一个专门的库作为 CsvHelper(添加注释)。
    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 2021-02-15
    • 2015-09-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 2022-10-19
    • 1970-01-01
    相关资源
    最近更新 更多