Ao ler um arquivo CSV usando um DataReader e o provedor de dados OLEDB Jet, como posso controlar tipos de dados de coluna?

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

  •  02-07-2019
  •  | 
  •  

Pergunta

Na minha C # aplicativo que eu estou usando o provedor de dados Microsoft Jet OLEDB para ler um arquivo CSV. Os olhares da cadeia de conexão como este:

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

Eu abro um OleDbConnection ADO.NET usando essa seqüência de conexão e selecione todas as linhas do arquivo CSV com o comando:

select * from Data.csv

Quando abro um OleDbDataReader e examinar os tipos de dados das colunas ele retorna, acho que algo na pilha tentou adivinhar os tipos de dados com base na primeira linha de dados no arquivo. Por exemplo, suponha que o arquivo CSV contém:

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

Chamar o método OleDbDataReader.GetDataTypeName para a coluna Casa irá revelar que a coluna foi dado o tipo de dados "DBTYPE_I4", para que todos os valores lidos a partir dele são interpretados como números inteiros. Meu problema é que a Casa deve ser uma string -. Quando tento ler o valor casa da segunda linha, o OleDbDataReader retorna null

Como posso saber ou o provedor de banco de dados Jet ou o OleDbDataReader para interpretar uma coluna como strings em vez de números?

Foi útil?

Solução

Há um arquivo de esquema que você pode criar que diria ADO.NET como interpretar o CSV -. Em vigor dando-lhe uma estrutura

Tente isto: http://www.aspdotnetcodes.com/Importing_CSV_Database_Schema.ini.aspx

Outras dicas

Para expandir a resposta de Marc, eu preciso criar um arquivo de texto chamado Schema.ini e colocá-lo no mesmo diretório que o arquivo CSV. Bem como tipos de colunas, este arquivo pode especificar o formato de arquivo, formato de data e hora, configurações regionais, e os nomes das colunas, se eles não estão incluídos no arquivo.

Para tornar o exemplo que dei no trabalho questão, o arquivo esquema deve ficar assim:

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

Eu também poderia tentar isso para tornar o provedor de dados examinar todas as linhas no arquivo antes de ele tenta adivinhar os tipos de dados:

[Data.csv]
ColNameHeader=true
MaxScanRows=0

Na vida real, os meus importações de aplicação dados de arquivos com nomes dinâmicos, então eu tenho que criar um arquivo Schema.ini on the fly e escrevê-lo para o mesmo diretório que o arquivo CSV antes de eu abrir a minha ligação.

Mais detalhes podem ser encontrados aqui - http: // msdn.microsoft.com/en-us/library/ms709353(VS.85).aspx -. ou através de pesquisa na Biblioteca MSDN para "arquivo Schema.ini"

Por favor, verifique

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

Você precisa dizer ao motorista para fazer a varredura de todas as linhas para determinar o esquema. Caso contrário, se as primeiras linhas são numéricos e os restantes são alfanumérico, as células alfanuméricos ficará em branco.

Como Rory , descobri que eu precisava para criar um arquivo schema.ini dinamicamente porque não há nenhuma maneira de programaticamente dizer ao motorista para digitalizar todas as linhas. (Isto não é o caso de arquivos do Excel)

Você deve ter MaxScanRows=0 em sua schema.ini

Aqui está um exemplo de código:

    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);
            }
        }
    }

Você vai precisar fazer alguma modificação se você estiver executando esta no mesmo diretório em vários threads ao mesmo tempo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top