How to read a CSV file into a .NET Datatable

后端 未结 22 2109
野性不改
野性不改 2020-11-22 05:12

How can I load a CSV file into a System.Data.DataTable, creating the datatable based on the CSV file?

Does the regular ADO.net functionality allow this?

相关标签:
22条回答
  • 2020-11-22 05:56

    this is the code i use it but your apps must run with net version 3.5

    private void txtRead_Click(object sender, EventArgs e)
            {
               // var filename = @"d:\shiptest.txt";
    
                openFileDialog1.InitialDirectory = "d:\\";
                openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
                DialogResult result = openFileDialog1.ShowDialog();
                if (result == DialogResult.OK)
                {
                    if (openFileDialog1.FileName != "")
                    {
                        var reader = ReadAsLines(openFileDialog1.FileName);
    
                        var data = new DataTable();
    
                        //this assume the first record is filled with the column names
                        var headers = reader.First().Split(',');
                        foreach (var header in headers)
                        {
                            data.Columns.Add(header);
                        }
    
                        var records = reader.Skip(1);
                        foreach (var record in records)
                        {
                            data.Rows.Add(record.Split(','));
                        }
    
                        dgList.DataSource = data;
                    }
                }
            }
    
            static IEnumerable<string> ReadAsLines(string filename)
            {
                using (StreamReader reader = new StreamReader(filename))
                    while (!reader.EndOfStream)
                        yield return reader.ReadLine();
            }
    
    0 讨论(0)
  • 2020-11-22 05:56

    Just sharing this extension methods, I hope that it can help someone.

    public static List<string> ToCSV(this DataSet ds, char separator = '|')
    {
        List<string> lResult = new List<string>();
    
        foreach (DataTable dt in ds.Tables)
        {
            StringBuilder sb = new StringBuilder();
            IEnumerable<string> columnNames = dt.Columns.Cast<DataColumn>().
                                              Select(column => column.ColumnName);
            sb.AppendLine(string.Join(separator.ToString(), columnNames));
    
            foreach (DataRow row in dt.Rows)
            {
                IEnumerable<string> fields = row.ItemArray.Select(field =>
                  string.Concat("\"", field.ToString().Replace("\"", "\"\""), "\""));
                sb.AppendLine(string.Join(separator.ToString(), fields));
            }
    
            lResult.Add(sb.ToString());
        }
        return lResult;
    }
    
    public static DataSet CSVtoDataSet(this List<string> collectionCSV, char separator = '|')
    {
        var ds = new DataSet();
    
        foreach (var csv in collectionCSV)
        {
            var dt = new DataTable();
    
            var readHeader = false;
            foreach (var line in csv.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
            {
                if (!readHeader)
                {
                    foreach (var c in line.Split(separator))
                        dt.Columns.Add(c);
                }
                else
                {
                    dt.Rows.Add(line.Split(separator));
                }
            }
    
            ds.Tables.Add(dt);
        }
    
        return ds;
    }
    
    0 讨论(0)
  • 2020-11-22 05:57

    For those of you wishing not to use an external library, and prefer not to use OleDB, see the example below. Everything I found was either OleDB, external library, or simply splitting based on a comma! For my case OleDB was not working so I wanted something different.

    I found an article by MarkJ that referenced the Microsoft.VisualBasic.FileIO.TextFieldParser method as seen here. The article is written in VB and doesn't return a datatable, so see my example below.

    public static DataTable LoadCSV(string path, bool hasHeader)
        {
            DataTable dt = new DataTable();
    
            using (var MyReader = new Microsoft.VisualBasic.FileIO.TextFieldParser(path))
            {
                MyReader.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited;
                MyReader.Delimiters = new String[] { "," };
    
                string[] currentRow;
    
                //'Loop through all of the fields in the file.  
                //'If any lines are corrupt, report an error and continue parsing.  
                bool firstRow = true;
                while (!MyReader.EndOfData)
                {
                    try
                    {
                        currentRow = MyReader.ReadFields();
    
                        //Add the header columns
                        if (hasHeader && firstRow)
                        {
                            foreach (string c in currentRow)
                            {
                                dt.Columns.Add(c, typeof(string));
                            }
    
                            firstRow = false;
                            continue;
                        }
    
                        //Create a new row
                        DataRow dr = dt.NewRow();
                        dt.Rows.Add(dr);
    
                        //Loop thru the current line and fill the data out
                        for(int c = 0; c < currentRow.Count(); c++)
                        {
                            dr[c] = currentRow[c];
                        }
                    }
                    catch (Microsoft.VisualBasic.FileIO.MalformedLineException ex)
                    {
                        //Handle the exception here
                    }
                }
            }
    
            return dt;
        }
    
    0 讨论(0)
  • 2020-11-22 05:58

    I came across this piece of code that uses Linq and regex to parse a CSV file. The refering article is now over a year and a half old, but have not come across a neater way to parse a CSV using Linq (and regex) than this. The caveat is the regex applied here is for comma delimited files (will detect commas inside quotes!) and that it may not take well to headers, but there is a way to overcome these). Take a peak:

    Dim lines As String() = System.IO.File.ReadAllLines(strCustomerFile)
    Dim pattern As String = ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"
    Dim r As System.Text.RegularExpressions.Regex = New System.Text.RegularExpressions.Regex(pattern)
    Dim custs = From line In lines _
                Let data = r.Split(line) _
                    Select New With {.custnmbr = data(0), _
                                     .custname = data(1)}
    For Each cust In custs
        strCUSTNMBR = Replace(cust.custnmbr, Chr(34), "")
        strCUSTNAME = Replace(cust.custname, Chr(34), "")
    Next
    
    0 讨论(0)
  • 2020-11-22 05:59

    Very basic answer: if you don't have a complex csv that can use a simple split function this will work well for importing (note this imports as strings, i do datatype conversions later if i need to)

     private DataTable csvToDataTable(string fileName, char splitCharacter)
        {                
            StreamReader sr = new StreamReader(fileName);
            string myStringRow = sr.ReadLine();
            var rows = myStringRow.Split(splitCharacter);
            DataTable CsvData = new DataTable();
            foreach (string column in rows)
            {
                //creates the columns of new datatable based on first row of csv
                CsvData.Columns.Add(column);
            }
            myStringRow = sr.ReadLine();
            while (myStringRow != null)
            {
                //runs until string reader returns null and adds rows to dt 
                rows = myStringRow.Split(splitCharacter);
                CsvData.Rows.Add(rows);
                myStringRow = sr.ReadLine();
            }
            sr.Close();
            sr.Dispose();
            return CsvData;
        }
    

    My method if I am importing a table with a string[] separater and handles the issue where the current line i am reading may have went to the next line in the csv or text file <- IN which case i want to loop until I get to the total number of lines in the first row (columns)

    public static DataTable ImportCSV(string fullPath, string[] sepString)
        {
            DataTable dt = new DataTable();
            using (StreamReader sr = new StreamReader(fullPath))
            {
               //stream uses using statement because it implements iDisposable
                string firstLine = sr.ReadLine();
                var headers = firstLine.Split(sepString, StringSplitOptions.None);
                foreach (var header in headers)
                {
                   //create column headers
                    dt.Columns.Add(header);
                }
                int columnInterval = headers.Count();
                string newLine = sr.ReadLine();
                while (newLine != null)
                {
                    //loop adds each row to the datatable
                    var fields = newLine.Split(sepString, StringSplitOptions.None); // csv delimiter    
                    var currentLength = fields.Count();
                    if (currentLength < columnInterval)
                    {
                        while (currentLength < columnInterval)
                        {
                           //if the count of items in the row is less than the column row go to next line until count matches column number total
                            newLine += sr.ReadLine();
                            currentLength = newLine.Split(sepString, StringSplitOptions.None).Count();
                        }
                        fields = newLine.Split(sepString, StringSplitOptions.None);
                    }
                    if (currentLength > columnInterval)
                    {  
                        //ideally never executes - but if csv row has too many separators, line is skipped
                        newLine = sr.ReadLine();
                        continue;
                    }
                    dt.Rows.Add(fields);
                    newLine = sr.ReadLine();
                }
                sr.Close();
            }
    
            return dt;
        }
    
    0 讨论(0)
  • 2020-11-22 06:00
     Public Function ReadCsvFileToDataTable(strFilePath As String) As DataTable
        Dim dtCsv As DataTable = New DataTable()
        Dim Fulltext As String
        Using sr As StreamReader = New StreamReader(strFilePath)
            While Not sr.EndOfStream
                Fulltext = sr.ReadToEnd().ToString()
                Dim rows As String() = Fulltext.Split(vbLf)
                For i As Integer = 0 To rows.Count() - 1 - 1
                    Dim rowValues As String() = rows(i).Split(","c)
                    If True Then
                        If i = 0 Then
                            For j As Integer = 0 To rowValues.Count() - 1
                                dtCsv.Columns.Add(rowValues(j))
                            Next
                        Else
                            Dim dr As DataRow = dtCsv.NewRow()
                            For k As Integer = 0 To rowValues.Count() - 1
                                dr(k) = rowValues(k).ToString()
                            Next
                            dtCsv.Rows.Add(dr)
                        End If
                    End If
                Next
            End While
        End Using
        Return dtCsv
    End Function
    
    0 讨论(0)
提交回复
热议问题