Как при чтении файла CSV с помощью DataReader и поставщика данных OLEDB Jet можно управлять типами данных столбцов?

StackOverflow https://stackoverflow.com/questions/115658

  •  02-07-2019
  •  | 
  •  

Вопрос

В моем приложении 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

Вызов метода OleDbDataReader.GetDataTypeName для столбца House покажет, что столбцу присвоен тип данных «DBTYPE_I4», поэтому все значения, считанные из него, интерпретируются как целые числа.Моя проблема в том, что House должен быть строкой: когда я пытаюсь прочитать значение House из второй строки, OleDbDataReader возвращает значение null.

Как я могу указать поставщику базы данных Jet или OleDbDataReader интерпретировать столбец как строки, а не числа?

Это было полезно?

Решение

Вы можете создать файл схемы, который сообщит ADO.NET, как интерпретировать CSV, фактически придавая ему структуру.

Попробуй это: http://www.aspdotnetcodes.com/Importing_CSV_Database_Schema.ini.aspx

Другие советы

Чтобы расширить ответ Марка, мне нужно создать текстовый файл с именем Schema.ini и поместить его в тот же каталог, что и файл CSV.Помимо типов столбцов, в этом файле можно указать формат файла, формат даты и времени, региональные настройки и имена столбцов, если они не включены в файл.

Чтобы пример, который я привел в вопросе, работал, файл схемы должен выглядеть следующим образом:

[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».

пожалуйста, проверьте

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"];
    }
}

Вам нужно указать драйверу, чтобы он сканировал все строки, чтобы определить схему.В противном случае, если первые несколько строк являются числовыми, а остальные — буквенно-цифровыми, буквенно-цифровые ячейки будут пустыми.

Нравиться Рори, я обнаружил, что мне нужно создать файл Schema.ini динамически, поскольку не существует способа программно указать драйверу сканировать все строки.(это не относится к файлам Excel)

Вы должны иметь MaxScanRows=0 в вашей схеме.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);
            }
        }
    }

Вам нужно будет внести некоторые изменения, если вы запускаете это в одном и том же каталоге в нескольких потоках одновременно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top