Search code examples
c#csvdatatableimport-csvcsvtotable

C# Reading CSV to DataTable and Invoke Rows/Columns


i am currently working on a small Project and i got stuck with a Problem i currently can not manage to solve...

I have multiple ".CSV" Files i want to read, they all have the same Data just with different Values.

Header1;Value1;Info1
Header2;Value2;Info2
Header3;Value3;Info3

While reading the first File i Need to Create the Headers. The Problem is they are not splited in Columns but in rows (as you can see above Header1-Header3).

Then it Needs to read the Value 1 - Value 3 (they are listed in the 2nd Column) and on top of that i Need to create another Header -> Header4 with the data of "Info2" which is always placed in Column 3 and Row 2 (the other values of Column 3 i can ignore).

So the Outcome after the first File should look like this:

Header1;Header2;Header3;Header4;
Value1;Value2;Value3;Info2;

And after multiple files it sohuld be like this:

Header1;Header2;Header3;Header4;
Value1;Value2;Value3;Value4;
Value1b;Value2b;Value3b;Value4b;
Value1c;Value2c;Value3c;Value4c;

I tried it with OleDB but i get the Error "missing ISAM" which i cant mange to fix. The Code i Used is the following:

public DataTable ReadCsv(string fileName)
    {
        DataTable dt = new DataTable("Data");
       /* using (OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"" + 
            Path.GetDirectoryName(fileName) + "\";Extendet Properties ='text;HDR=yes;FMT=Delimited(,)';"))
        */
        using (OleDbConnection cn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
            Path.GetDirectoryName(fileName) + ";Extendet Properties ='text;HDR=yes;FMT=Delimited(,)';"))
        {
            using(OleDbCommand cmd = new OleDbCommand(string.Format("select *from [{0}]", new FileInfo(fileName).Name,cn)))
            {
                cn.Open();
                using(OleDbDataAdapter adapter = new OleDbDataAdapter(cmd))
                {
                    adapter.Fill(dt);
                }
            }
        }


        return dt;
    }

Another attempt i did was using StreamReader. But the Headers are in the wrong place and i dont know how to Change this + do this for every file. the Code i tried is the following:

  public static DataTable ReadCsvFilee(string path)
    {  

        DataTable oDataTable = new DataTable();
        var fileNames = Directory.GetFiles(path);
        foreach (var fileName in fileNames)

        {

            //initialising a StreamReader type variable and will pass the file location
            StreamReader oStreamReader = new StreamReader(fileName);

            // CONTROLS WHETHER WE SKIP A ROW OR NOT
            int RowCount = 0;
            // CONTROLS WHETHER WE CREATE COLUMNS OR NOT
            bool hasColumns = false;
            string[] ColumnNames = null;
            string[] oStreamDataValues = null;
            //using while loop read the stream data till end
            while (!oStreamReader.EndOfStream)
            { 

                String oStreamRowData = oStreamReader.ReadLine().Trim();
                if (oStreamRowData.Length > 0)
                { 

                    oStreamDataValues = oStreamRowData.Split(';');
                    //Bcoz the first row contains column names, we will poluate 
                    //the column name by
                    //reading the first row and RowCount-0 will be true only once
                    // CHANGE TO CHECK FOR COLUMNS CREATED                      
                    if (!hasColumns)
                    {
                        ColumnNames = oStreamRowData.Split(';');

                        //using foreach looping through all the column names
                        foreach (string csvcolumn in ColumnNames)
                        {
                            DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));

                            //setting the default value of empty.string to newly created column
                            oDataColumn.DefaultValue = string.Empty;

                            //adding the newly created column to the table
                            oDataTable.Columns.Add(oDataColumn);
                        }
                        // SET COLUMNS CREATED
                        hasColumns = true;
                        // SET RowCount TO 0 SO WE KNOW TO SKIP COLUMNS LINE
                        RowCount = 0;
                    }
                    else
                    {
                        // IF RowCount IS 0 THEN SKIP COLUMN LINE
                        if (RowCount++ == 0) continue;
                        //creates a new DataRow with the same schema as of the oDataTable            
                        DataRow oDataRow = oDataTable.NewRow();

                        //using foreach looping through all the column names
                        for (int i = 0; i < ColumnNames.Length; i++)
                        {
                            oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
                        }

                        //adding the newly created row with data to the oDataTable       
                        oDataTable.Rows.Add(oDataRow);
                    }

                }
            }
            //close the oStreamReader object
            oStreamReader.Close();
            //release all the resources used by the oStreamReader object
            oStreamReader.Dispose();
        }
            return oDataTable;
        }

I am thankful for everyone who is willing to help. And Thanks for reading this far!

Sincerely yours


Solution

  • (Adding as another answer just to make it uncluttered)

    void ProcessMyFiles(string folderName)
    {
        List<MyData> d = new List<MyData>();
        var files = Directory.GetFiles(folderName);
        foreach (var file in files)
        {
            OpenAndParse(file, d);
        }
    
        string[] headers = GetHeaders(files[0]);
        DataGridView dgv = new DataGridView {Dock=DockStyle.Fill};
        dgv.DataSource = d;
        dgv.ColumnAdded += (sender, e) => {e.Column.HeaderText = headers[e.Column.Index];};
    
        Form f = new Form();
        f.Controls.Add(dgv);
        f.Show();
    }
    
    string[] GetHeaders(string filename)
    {
        var lines = File.ReadAllLines(filename);
        var parsed = lines.Select(l => l.Split(';')).ToArray();
        return new string[] { parsed[0][0], parsed[1][0], parsed[2][0], parsed[1][0] };
    }
    
    void OpenAndParse(string filename, List<MyData> d)
    {
        var lines = File.ReadAllLines(filename);
        var parsed = lines.Select(l => l.Split(';')).ToArray();
        var data = new MyData
        {
            Col1 = parsed[0][1],
            Col2 = parsed[1][1],
            Col3 = parsed[2][1],
            Col4 = parsed[1][2]
        };
        d.Add(data);
    }
    
    public class MyData
    {
        public string Col1 { get; set; }
        public string Col2 { get; set; }
        public string Col3 { get; set; }
        public string Col4 { get; set; }
    }