Search code examples
c#importcsvhelper

Importing .csv into DataGridView - various CSV files with different numbers of columns


I would like to ask for your advice. I need to import a .csv file into a DataGridView. I would like the number of columns in the DataGridView to change with each import, depending on the number of columns in the .csv file. I have managed to achieve that, as after the import, the DataGridView creates the correct number of columns based on the .csv file. However, the data is not displayed in the table. Thank you for your guidance. In my project i use CsvHelper.

using CsvHelper;
using CsvHelper.Configuration;
using Microsoft.VisualBasic.FileIO;
using System;
using System.Globalization;
using System.IO;
using System.Windows.Forms;

namespace ImportCSV
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void loadCSV_button_Click(object sender, EventArgs e)
        {
            string csvFilePath = "C:\\LoadCSV\\addresses.csv"; 
            int numberOfColumns = CountColumns(csvFilePath);
            CreateDataGridViewColumns(numberOfColumns);
            LoadDataIntoDataGridView(csvFilePath);
        }
        private int CountColumns(string filePath)
        {
            int columnCount = 0;

            using (TextFieldParser parser = new TextFieldParser(filePath))
            {
                parser.SetDelimiters(",");
                parser.HasFieldsEnclosedInQuotes = true;

                if (!parser.EndOfData)
                {
                    string[] fields = parser.ReadFields();
                    columnCount = fields.Length;
                }
            }

            return columnCount;
        }

        private void CreateDataGridViewColumns(int numberOfColumns)
        {
            for (int i = 0; i < numberOfColumns; i++)
            {
                DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
                column.Name = $"Column{i + 1}";
                column.HeaderText = $"Column {i + 1}";
                dataGridView1.Columns.Add(column);
            }
        }

        private void LoadDataIntoDataGridView(string filePath)
        {
            using (var reader = new StreamReader(filePath))
            using (var csv = new CsvReader(reader, new    CsvConfiguration(CultureInfo.InvariantCulture) ))
            {
                var records = csv.GetRecords<dynamic>();
                foreach (var record in records)
                {
                    
                    DataGridViewRow row = new DataGridViewRow();
                    foreach (var property in record.GetType().GetProperties())
                    {
                                      
                        DataGridViewCell cell = new DataGridViewTextBoxCell();
                       
                      
                        cell.Value = property.GetValue(record, null);
                        dataGridView1.DataSource = record;
                        row.Cells.Add(cell);
                    }
                    dataGridView1.Rows.Add(row);
                    
                }
            }
        }

        
    }
}


Solution

  • I would suggest that you convert CSV to DataTable (https://learn.microsoft.com/en-us/dotnet/api/system.data.datatable?view=net-8.0) since you don't know for sure the number of columns to be imported

    public DataTable GetDataTable(string csvFilePath, char delim = ',', bool quoted = true)
    {
        var table = new DataTable();
        using var stream = File.Open(csvFilePath,FileMode.Open,FileAccess.Read);
        using var reader = new StreamReader(stream);
        bool firstRow = true;
        while(!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            var fields = line.Split(delim).Select(f => quoted ? f.Trim('"') : f);
            if(firstRow)
            {
                table.Columns.AddRange(fields.Select(f => new DataColumn(f)).ToArray());
            }
            else
            {
                table.Rows.Add(fields.Cast<object?>().ToArray());
            }
            firstRow = false;
        }
        reader.Close();
        stream.Close();
        return table;
    }
    

    Then, to load the datagridview with new CSV file, use the following code:

    dataGridView1.DataSource = GetDataTable("C:/LoadCSV/addresses.csv");
    

    I have written this code on the fly and have not tested it, but it should work