17 ответов:
вот отличный класс, который будет копировать данные CSV в datatable, используя структуру данных для создания DataTable:
портативный и эффективный универсальный парсер для плоских файлов
Он прост в настройке и прост в использовании. Я призываю вас взглянуть.
Я использую
OleDbпровайдер. Однако, он имеет проблемы, если Вы читаете в строках, которые имеют числовые значения, но вы хотите их рассматривать как текст. Однако вы можете обойти эту проблему, создав . Вот мой метод, который я использовал:// using System.Data; // using System.Data.OleDb; // using System.Globalization; // using System.IO; static DataTable GetDataTableFromCsv(string path, bool isFirstRowHeader) { string header = isFirstRowHeader ? "Yes" : "No"; string pathOnly = Path.GetDirectoryName(path); string fileName = Path.GetFileName(path); string sql = @"SELECT * FROM [" + fileName + "]"; using(OleDbConnection connection = new OleDbConnection( @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + pathOnly + ";Extended Properties=\"Text;HDR=" + header + "\"")) using(OleDbCommand command = new OleDbCommand(sql, connection)) using(OleDbDataAdapter adapter = new OleDbDataAdapter(command)) { DataTable dataTable = new DataTable(); dataTable.Locale = CultureInfo.CurrentCulture; adapter.Fill(dataTable); return dataTable; } }
Я решил использовать читатель Csv Себастьена Лориона.
предложение Джея Риггса также является отличным решением, но мне просто не нужны все функции, которые это Андрей Rissing анализатор обеспечивает.
обновление 10/25/2010
после читатель Csv Себастьена Лориона в моем проекте почти полтора года я обнаружил, что он выдает исключения при разборе некоторых csv-файлов, которые я считаю правильно построенный.
Итак, я переключился на Андрей Rissing анализатор и это, кажется, делает гораздо лучше.
обновление 22.09.2014
в эти дни я в основном использую этот метод расширения для чтения с разделителями текст:
https://www.nuget.org/packages/CoreTechs.Common/
обновление 2/20/2015
пример:
var csv = @"Name, Age Ronnie, 30 Mark, 40 Ace, 50"; TextReader reader = new StringReader(csv); var table = new DataTable(); using(var it = reader.ReadCsvWithHeader().GetEnumerator()) { if (!it.MoveNext()) return; foreach (var k in it.Current.Keys) table.Columns.Add(k); do { var row = table.NewRow(); foreach (var k in it.Current.Keys) row[k] = it.Current[k]; table.Rows.Add(row); } while (it.MoveNext()); }
- Эй, работающего 100%
public static DataTable ConvertCSVtoDataTable(string strFilePath) { DataTable dt = new DataTable(); using (StreamReader sr = new StreamReader(strFilePath)) { string[] headers = sr.ReadLine().Split(','); foreach (string header in headers) { dt.Columns.Add(header); } while (!sr.EndOfStream) { string[] rows = sr.ReadLine().Split(','); DataRow dr = dt.NewRow(); for (int i = 0; i < headers.Length; i++) { dr[i] = rows[i]; } dt.Rows.Add(dr); } } return dt; }CSV Image
таблица данных, импортированных
мы всегда использовали реактивный самолет.Oledb драйвер, пока мы не начали переходить на 64-битные приложения. Microsoft не выпустила и не выпустит 64-битный драйвер Jet. Вот простое решение, которое мы придумали, что использует файл.ReadAllLines и строка.Разделить для чтения и анализа CSV-файла и вручную загрузить DataTable. Как отмечалось выше, он не обрабатывает ситуацию, когда одно из значений столбца содержит запятую. Мы используем это в основном для чтения пользовательских файлов конфигурации-хорошая часть об использовании CSV файлы, которые можно редактировать их в Excel.
string CSVFilePathName = @"C:\test.csv"; string[] Lines = File.ReadAllLines(CSVFilePathName); string[] Fields; Fields = Lines[0].Split(new char[] { ',' }); int Cols = Fields.GetLength(0); DataTable dt = new DataTable(); //1st row must be column names; force lower case to ensure matching later on. for (int i = 0; i < Cols; i++) dt.Columns.Add(Fields[i].ToLower(), typeof(string)); DataRow Row; for (int i = 1; i < Lines.GetLength(0); i++) { Fields = Lines[i].Split(new char[] { ',' }); Row = dt.NewRow(); for (int f = 0; f < Cols; f++) Row[f] = Fields[f]; dt.Rows.Add(Row); }
это код, который я использую, но ваши приложения должны работать с net версии 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(); }
public DataTable CsvFileToDatatable(string path, bool IsFirstRowHeader)//here Path is root of file and IsFirstRowHeader is header is there or not { string header = "No"; string sql = string.Empty; DataTable dataTable = null; string pathOnly = string.Empty; string fileName = string.Empty; try { pathOnly = Path.GetDirectoryName(path); fileName = Path.GetFileName(path); sql = @"SELECT * FROM [" + fileName + "]"; if (IsFirstRowHeader) { header = "Yes"; } using (OleDbConnection connection = new OleDbConnection( @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + pathOnly + ";Extended Properties=\"Text;HDR=" + header + "\"")) { using (OleDbCommand command = new OleDbCommand(sql, connection)) { using (OleDbDataAdapter adapter = new OleDbDataAdapter(command)) { dataTable = new DataTable(); dataTable.Locale = CultureInfo.CurrentCulture; adapter.Fill(dataTable); } } } } finally { } return dataTable; }
я наткнулся на этот фрагмент кода, который использует Linq и regex для анализа CSV-файла. Ссылающаяся статья теперь старше полутора лет, но не встретила более аккуратного способа анализа CSV с использованием Linq (и regex), чем это. Предостережение-это регулярное выражение, применяемое здесь для файлов с разделителями-запятыми (будет обнаруживать запятые внутри кавычек!) и что это может быть не очень хорошо для заголовков, но есть способ преодолеть их). Возьмите пик:
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
вы можете достичь этого с помощью Microsoft.Визуальная основа.FileIO.Textfieldparser dll в C#
static void Main() { string csv_file_path=@"C:\Users\Administrator\Desktop\test.csv"; DataTable csvData = GetDataTabletFromCSVFile(csv_file_path); Console.WriteLine("Rows count:" + csvData.Rows.Count); Console.ReadLine(); } private static DataTable GetDataTabletFromCSVFile(string csv_file_path) { DataTable csvData = new DataTable(); try { using(TextFieldParser csvReader = new TextFieldParser(csv_file_path)) { csvReader.SetDelimiters(new string[] { "," }); csvReader.HasFieldsEnclosedInQuotes = true; string[] colFields = csvReader.ReadFields(); foreach (string column in colFields) { DataColumn datecolumn = new DataColumn(column); datecolumn.AllowDBNull = true; csvData.Columns.Add(datecolumn); } while (!csvReader.EndOfData) { string[] fieldData = csvReader.ReadFields(); //Making empty value as null for (int i = 0; i < fieldData.Length; i++) { if (fieldData[i] == "") { fieldData[i] = null; } } csvData.Rows.Add(fieldData); } } } catch (Exception ex) { } return csvData; }
лучший вариант, который я нашел, и он решает проблемы, когда у вас могут быть установлены разные версии Office, а также 32/64-битные проблемы, такие как Чак Бевитт упомянул, составляет FileHelpers.
Он может быть добавлен к вашим ссылкам на проект с помощью NuGet, и он предоставляет однострочное решение:
CommonEngine.CsvToDataTable(path, "ImportRecord", ',', true);
для тех из вас, кто не хочет использовать внешнюю библиотеку и предпочитает не использовать OleDB, см. пример ниже. Все, что я нашел, было либо OleDB, внешняя библиотека, либо просто разделение на основе запятой! Для моего случая OleDB не работал, поэтому я хотел что-то другое.
Я нашел статью MarkJ, которая ссылается на Microsoft.Визуальная основа.FileIO.TextFieldParser метод, как видно здесь. Статья написана на VB и не возвращает datatable, поэтому см. Мой пример ниже.
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; }
очень простой ответ: если у вас нет сложного csv, который может использовать простую функцию разделения, это будет хорошо работать для импорта (обратите внимание, что это импортирует как строки, я делаю преобразования типов данных позже, если мне нужно)
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; }мой метод, если я импортирую таблицу с разделителем string[] и обрабатывает проблему, когда текущая строка, которую я читаю, возможно, перешла к следующей строке в csv или текстовом файле
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; }
изменено от Mr ChuckBevitt
рабочего раствора:
string CSVFilePathName = APP_PATH + "Facilities.csv"; string[] Lines = File.ReadAllLines(CSVFilePathName); string[] Fields; Fields = Lines[0].Split(new char[] { ',' }); int Cols = Fields.GetLength(0); DataTable dt = new DataTable(); //1st row must be column names; force lower case to ensure matching later on. for (int i = 0; i < Cols-1; i++) dt.Columns.Add(Fields[i].ToLower(), typeof(string)); DataRow Row; for (int i = 0; i < Lines.GetLength(0)-1; i++) { Fields = Lines[i].Split(new char[] { ',' }); Row = dt.NewRow(); for (int f = 0; f < Cols-1; f++) Row[f] = Fields[f]; dt.Rows.Add(Row); }
вот решение, которое использует ADO.Net текстовый драйвер ODBC:
Dim csvFileFolder As String = "C:\YourFileFolder" Dim csvFileName As String = "YourFile.csv" 'Note that the folder is specified in the connection string, 'not the file. That's specified in the SELECT query, later. Dim connString As String = "Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq=" _ & csvFileFolder & ";Extended Properties=""Text;HDR=No;FMT=Delimited""" Dim conn As New Odbc.OdbcConnection(connString) 'Open a data adapter, specifying the file name to load Dim da As New Odbc.OdbcDataAdapter("SELECT * FROM [" & csvFileName & "]", conn) 'Then fill a data table, which can be bound to a grid Dim dt As New DataTableda.Fill(dt) grdCSVData.DataSource = dtпосле заполнения, вы можете оценить свойства datatable, как ColumnName, чтобы сделать использовать все полномочия ADO.Net объекты данных.
в VS2008 вы можете использовать Linq для достижения того же эффекта.
Примечание: это может быть дубликат этой Итак, вопрос.
public class Csv { public static DataTable DataSetGet(string filename, string separatorChar, out List<string> errors) { errors = new List<string>(); var table = new DataTable("StringLocalization"); using (var sr = new StreamReader(filename, Encoding.Default)) { string line; var i = 0; while (sr.Peek() >= 0) { try { line = sr.ReadLine(); if (string.IsNullOrEmpty(line)) continue; var values = line.Split(new[] {separatorChar}, StringSplitOptions.None); var row = table.NewRow(); for (var colNum = 0; colNum < values.Length; colNum++) { var value = values[colNum]; if (i == 0) { table.Columns.Add(value, typeof (String)); } else { row[table.Columns[colNum]] = value; } } if (i != 0) table.Rows.Add(row); } catch(Exception ex) { errors.Add(ex.Message); } i++; } } return table; } }
не могу удержаться, чтобы не добавить свой собственный спин к этому. Это намного лучше и компактнее, чем то, что я использовал в прошлом.
такое решение:
- не зависит от драйвера базы данных или сторонней библиотеки.
- не подведет при дублировании имен столбцов
- обрабатывает запятые в данных
- ручки любой разделитель, а не только запятые (хотя это по умолчанию)
вот что я придумал с:
Public Function ToDataTable(FileName As String, Optional Delimiter As String = ",") As DataTable ToDataTable = New DataTable Using TextFieldParser As New Microsoft.VisualBasic.FileIO.TextFieldParser(FileName) With {.HasFieldsEnclosedInQuotes = True, .TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited, .TrimWhiteSpace = True} With TextFieldParser .SetDelimiters({Delimiter}) .ReadFields.ToList.Unique.ForEach(Sub(x) ToDataTable.Columns.Add(x)) ToDataTable.Columns.Cast(Of DataColumn).ToList.ForEach(Sub(x) x.AllowDBNull = True) Do Until .EndOfData ToDataTable.Rows.Add(.ReadFields.Select(Function(x) Text.BlankToNothing(x)).ToArray) Loop End With End Using End FunctionЭто зависит от метода расширения (
Unique) для обработки повторяющихся имен столбцов, которые будут найдены в качестве моего ответа в как добавить уникальные номера в список строки вот это
BlankToNothingвспомогательную функцию:Public Function BlankToNothing(ByVal Value As String) As Object If String.IsNullOrEmpty(Value) Then Return Nothing Return Value End Function
С Cinchoo ETL - библиотека с открытым исходным кодом, вы можете легко конвертировать CSV-файл в DataTable с несколькими строками кода.
using (var p = new ChoCSVReader(** YOUR CSV FILE **) .WithFirstLineHeader() ) { var dt = p.AsDataTable(); }для получения дополнительной информации, пожалуйста, посетите статью codeproject.
надеюсь, что это помогает.


Comments