15

在我的 C# 应用程序中,我使用 Microsoft Jet OLEDB 数据提供程序来读取 CSV 文件。连接字符串如下所示:

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Data;Extended Properties="text;HDR=Yes;FMT=Delimited

我使用该连接字符串打开一个 ADO.NET OleDbConnection 并使用以下命令从 CSV 文件中选择所有行:

select * from Data.csv

当我打开 OleDbDataReader 并检查它返回的列的数据类型时,我发现堆栈中的某些东西试图根据文件中的第一行数据来猜测数据类型。例如,假设 CSV 文件包含:

House,Street,Town
123,Fake Street,Springfield
12a,Evergreen Terrace,Springfield

为 House 列调用 OleDbDataReader.GetDataTypeName 方法将显示该列已被赋予数据类型“DBTYPE_I4”,因此从中读取的所有值都被解释为整数。我的问题是 House 应该是一个字符串 - 当我尝试从第二行读取 House 值时,OleDbDataReader 返回 null。

如何告诉 Jet 数据库提供程序或 OleDbDataReader 将列解释为字符串而不是数字?

4

4 回答 4

13

要扩展 Marc 的答案,我需要创建一个名为 Schema.ini 的文本文件,并将其放在与 CSV 文件相同的目录中。除列类型外,此文件还可以指定文件格式、日期时间格式、区域设置和列名(如果文件中未包含它们)。

为了使我在问题中给出的示例有效,Schema 文件应如下所示:

[Data.csv]
ColNameHeader=True
Col1=House Text
Col2=Street Text
Col3=Town Text

我也可以尝试让数据提供者在尝试猜测数据类型之前检查文件中的所有行:

[Data.csv]
ColNameHeader=true
MaxScanRows=0

在现实生活中,我的应用程序从具有动态名称的文件中导入数据,因此我必须在打开连接之前动态创建一个 Schema.ini 文件并将其写入与 CSV 文件相同的目录。

可以在此处找到更多详细信息 - http://msdn.microsoft.com/en-us/library/ms709353(VS.85).aspx - 或通过在 MSDN 库中搜索“Schema.ini 文件”。

于 2008-09-22T17:02:46.460 回答
10

您可以创建一个模式文件,它会告诉 ADO.NET 如何解释 CSV - 实际上是给它一个结构。

试试这个:http ://www.aspdotnetcodes.com/Importing_CSV_Database_Schema.ini.aspx

或最新的MS 文档

于 2008-09-22T15:50:27.557 回答
6

请检查

http://kbcsv.codeplex.com/

using (var reader = new CsvReader("data.csv"))
{
    reader.ReadHeaderRecord();
    foreach (var record in reader.DataRecords)
    {
        var name = record["Name"];
        var age = record["Age"];
    }
}
于 2011-10-05T07:28:08.117 回答
0

您需要告诉驱动程序扫描所有行以确定架构。否则,如果前几行是数字,其余行是字母数字,则字母数字单元格将为空白。

Rory一样,我发现我需要动态创建一个 schema.ini 文件,因为无法以编程方式告诉驱动程序扫描所有行。(这不是 excel 文件的情况)

你必须MaxScanRows=0在你的 schema.ini

这是一个代码示例:

    public static DataTable GetDataFromCsvFile(string filePath, bool isFirstRowHeader = true)
    {
        if (!File.Exists(filePath))
        {
            throw new FileNotFoundException("The path: " + filePath + " doesn't exist!");
        }

        if (!(Path.GetExtension(filePath) ?? string.Empty).ToUpper().Equals(".CSV"))
        {
            throw new ArgumentException("Only CSV files are supported");
        }
        var pathOnly = Path.GetDirectoryName(filePath);
        var filename = Path.GetFileName(filePath);
        var schemaIni =
            $"[{filename}]{Environment.NewLine}" +
            $"Format=CSVDelimited{Environment.NewLine}" +
            $"ColNameHeader={(isFirstRowHeader ? "True" : "False")}{Environment.NewLine}" +
            $"MaxScanRows=0{Environment.NewLine}" +
            $" ; scan all rows for data type{Environment.NewLine}" +
            $" ; This file was automatically generated";
        var schemaFile = pathOnly != null ? Path.Combine(pathOnly, "schema.ini") : "schema.ini";
        File.WriteAllText(schemaFile, schemaIni);

        try
        {
            var sqlCommand = $@"SELECT * FROM [{filename}]";

            var oleDbConnString =
                $"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={pathOnly};Extended Properties=\"Text;HDR={(isFirstRowHeader ? "Yes" : "No")}\"";

            using (var oleDbConnection = new OleDbConnection(oleDbConnString))
            using (var adapter = new OleDbDataAdapter(sqlCommand, oleDbConnection))
            using (var dataTable = new DataTable())
            {
                adapter.FillSchema(dataTable, SchemaType.Source);
                adapter.Fill(dataTable);
                return dataTable;
            }
        }
        finally
        {
            if (File.Exists(schemaFile))
            {
                File.Delete(schemaFile);
            }
        }
    }

如果您同时在多个线程中的同一目录上运行它,则需要进行一些修改。

于 2017-11-30T15:37:53.767 回答