C# Winforms - Проблема чтения файла CSV - PullRequest
0 голосов
/ 04 мая 2020

Я посмотрел все примеры чтения csv, которые могу найти, и я не совсем уверен, где я ошибаюсь с этим.

Я довольно новичок в C#, но мне это нравится до сих пор!

В любом случае, вот код, который отлично работает в большинстве случаев времени (вы можете видеть по комментариям, которые я пробовал в различных прочитанных вариантах):

StreamReader sr = new StreamReader(csvFileToImport);
                while (sr.EndOfStream != true)
                {
                    string line = sr.ReadLine();
                //string[] value = line.Split(new string[] { "\",\"" }, StringSplitOptions.None);
                //string[] value = line.Split(new string[] {","}, StringSplitOptions.None);
                //string[] value = line.Split(new string[] { "(?=(?:[^']*'[^']*')*[^']*$)" }, StringSplitOptions.None);
                //string[] value = line.Split(new string[] { "," }, StringSplitOptions.None);
                string[] value = Regex.Split(line, @"\s|[,]");

                StockItem si = new StockItem();
                    switch (stockFile.Supplier)
                    {
                        case "Leader":
                            si.Supplier = stockFile.Supplier;
                            si.Category = value[2].Replace("'", "''");
                            si.StockCode = value[11].Replace("'", "''");
                            si.Cost = Convert.ToDecimal(value[7]);
                            si.Description = value[4].Replace("'", "''");
                            si.Image = value[9].Replace("'", "''");
                            si.Manufacturer = value[10].Replace("'", "''");
                            si.Sell = Convert.ToDecimal(value[8]);
                            si.StockAdelaide = value[17].Replace("'", "''");
                            si.StockBrisbane = value[18].Replace("'", "''");

                            si.StockMelbourne = value[19].Replace("'", "''");
                            si.StockPerth = value[20].Replace("'", "''");
                            si.StockSydney = value[21].Replace("'", "''");
                            si.Subcategory = value[3].Replace("'", "''");

                            //Add line into db
                            string sql = "insert into Stock (Supplier, StockCode, Manufacturer, Category, Subcategory, Description, Cost, Sell, Image, StockPerth, StockAdelaide, StockSydney, StockBrisbane, StockMelbourne) values ('" + si.Supplier + "', '" + si.StockCode + "', '" + si.Manufacturer + "', '" + si.Category + "', '" + si.Subcategory + "', '" + si.Description + "', " + si.Cost + ", " + si.Sell + ", '" + si.Image + "', '" + si.StockPerth + "', '" + si.StockAdelaide + "', '" + si.StockSydney + "', '" + si.StockBrisbane + "', '" + si.StockMelbourne + "')";
                            cmd = new SqlCommand(sql, cn);
                            cmd.ExecuteNonQuery();
                            break;
                        default:
                            break;
                    }
                }
                success = true;
                cn.Close();

Я ссылался на 1-строчный CSV-файл, который не читается правильно, если кто-нибудь будет настолько хорош, чтобы посмотреть, я был бы очень рад!

Заранее спасибо, а также не стесняйтесь указывать на любой общий код, который я мог бы улучшить ... Я уверен, что есть много чего улучшить.

Еще раз спасибо:)

CSV Link: https://www.dropbox.com/s/nnaruu0twds3wrl/csv_error.csv?dl=0

ОБНОВЛЕНИЕ:

Извиняюсь за неясность, так как я читаю файл, я получаю следующую ошибку:

System.FormatException: 'Входная строка была не в правильном формате.'

Строка читается как:

"MECMD4VL2X426,ME,Memory,DDR-4 (Desktop),Corsair Vengeance LPX 8GB (2x4GB) DDR4 2666MHz C16 Desktop Gaming Memory Black,\"Corsair 8GB (2x4GB) DDR4 2666MHz Vengeance LPX Black"

Когда я запрашиваю массив, он показывает значения как:

value[0] "MECMD4VL2X426"
value[1] "ME"
value[2] "Memory"
value[3] "DDR-4"
value[4] "(Desktop)"
value[5] "Corsair"
value[6] "Vengeance"
value[7] "LPX"
...

Похоже, он застрял в скобках (это следует читать в значение [3]), а затем начинает разделять пробел вместо запятой.

Я рад использовать При необходимости сторонний csv-ридер, но я бы хотел понять, как он работает сам.

1 Ответ

1 голос
/ 04 мая 2020

Чтение CSV, которое вы используете string line = sr.ReadLine();, но RF C 4180 , 2.6 говорят нам, что поле, содержащее несколько строк, должно быть инкапсулировано с DQuote ".

Таким образом, чтение файла построчно будет проблемой, если в вашем документе существует поле с несколькими строками.
Я бы отбросил отработанное регулярное выражение и ReadLine и использовал бы более надежный синтаксический анализатор, такой как CSV Helper .

Затем определите объект, который вы хотите получить от CSV.

public class Leader
{
    public string LongColumn6 { get; set; }

    public string Supplier { get; set; }
    public string Category { get; set; }
    public string StockCode { get; set; }
    public Decimal Cost { get; set; }
    public string Description { get; set; }
    public string Image { get; set; }
    public string Manufacturer { get; set; }
    public Decimal Sell { get; set; }
    public string StockAdelaide { get; set; }
    public string StockBrisbane { get; set; }
    public string StockMelbourne { get; set; }
    public string StockPerth { get; set; }
    public string StockSydney { get; set; }
    public string Subcategory { get; set; }
}

И его соответствующий маппер: column & is Foo properties et c ..

public sealed class LeaderMap : ClassMap<Leader>
{
    public LeaderMap()
    {
        Map(m => m.LongColumn6).Index(5); // the column that cause the issue

        //complete the List
        Map(m => m.Category).Index(2);
        Map(m => m.StockCode).Index(11);
        Map(m => m.Cost).Index(7);
        Map(m => m.Description).Index(4);
    }
}

Тогда чтение простое:

using (var csvReader = new CsvReader(reader,  CultureInfo.InvariantCulture ))
{   
    csvReader.Configuration.HasHeaderRecord = false;
    csvReader.Configuration.RegisterClassMap<LeaderMap>();
    records = csvReader.GetRecords<Leader>().ToList();
}

Примечание что в этом живом демо . Я использовал StringReader для того, чтобы имитировать c File Reader.
Вы можете использовать File Reader и передать ему свой путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...