ATeDe Ответов: 1

Как конвертировать CSV в таблицы данных, используя LINQ в VB.NET


Sub NoNonsenseCSV2DataTable(CSVfile As String)
'A,B,C,D,E
'00001,4,1,2,3560
'00002,4,12,1,2000
'00003,1,1,2,4500
'00004,4,12,1,2538.63
'00005,1,1,2,3400
'00006,1,1,2,2996.48
Dim dTable As New DataTable
Using reader As New StreamReader(CSVfile)
    '_______________________________________________________________________
    Dim CSVheader As String = reader.ReadLine
    Dim Cols = (From s In CSVheader.Split(",") Select s).ToList()
    Dim setTblColumns = (From s In Cols Select dTable.Columns.Add(s, GetType(String))).ToList
    'TEST Dim getTblColumns As List(Of String) = (From c As DataColumn In dTable.Columns Select c.ColumnName).ToList()
    '_______________________________________________________________________
    Dim ReadToEnd As String = reader.ReadToEnd()
    Dim Rows = (From s In ReadToEnd.Split(vbLf) Select s).ToList()
    ' up to now everything goes well
    Dim getTblRows = (From z In Rows Select z.Split(",")).ToList()
    ' getting DataTable rows, OK

    'xxx Dim x As DataRow
    'xxx For Each s As String In Rows
    'xxx    x = dTable.NewRow()
    'xxx    x.ItemArray = s.Split(","c)
    'xxx    dTable.Rows.Add(x)
    'xxx Next
    '_______________________________________________________________________
End Using

End Sub


Что я уже пробовал:

Процедура работает на 100%, но я хочу изменить последнюю часть, чтобы получить преимущество LINQ: красивый код и лучшую производительность. Заранее спасибо за помощь
Атеде
Dim x As DataRow
For Each s As String In Rows
    x = dTable.NewRow()
    x.ItemArray = s.Split(","c)
    dTable.Rows.Add(x)
Next

1 Ответов

Рейтинг:
4

Maciej Los

Цитата:
Я бы получил преимущество LINQ: красивый код и лучшую производительность.

Я не уверен, что мое решение соответствует вашим критериям, но ... ..

Я бы изменился NoNonsenseCSV2DataTable(CSVfile As String) процедура в функцию. Видеть:
Public Function NoNonsenseCSV2DataTable(CSVfile As String) As DataTable
	Dim lines() As String  = File.ReadAllLines(CSVfile)
	
        'create DataTable
	Dim dt As DataTable = New DataTable()
	'get column names from first line and create an array of DataColumn
	Dim cols As DataColumn() = lines.Take(1) _
		.SelectMany(Function(x) x.Split(New String(){","}, StringSplitOptions.RemoveEmptyEntries)) _
		.Select(Function(x) New DataColumn(x, Type.GetType("System.String"))) _
		.ToArray()
	'add columns into DataTable
	dt.Columns.AddRange(cols)	
	
	'get rows - start from 2 line
	dt = lines.Skip(1) _
		.Select(Function(x) dt.LoadDataRow(x.Split(New String(){","}, StringSplitOptions.RemoveEmptyEntries), False)) _
		.ToArray() _
		.CopyToDataTable()
	'return DataTable
	Return dt

End Function


Использование:
Sub Main
    Dim sFileName As String = "FullFileNameOfCsvFile.csv"
    Dim myData As DataTable = NoNonsenseCSV2DataTable(sFileName)
    'myData is ready to use!

End Sub


Для получения более подробной информации, пожалуйста, смотрите:
Файл.Метод ReadAllLines (Строка) (System.IO)[^]
объект DataTable.Метод LoadDataRow (Object[], Boolean) (System.Data)[^]
Оператор Функции (Visual Basic) | Microsoft Docs[^]
Оператор Sub (Visual Basic) | Microsoft Docs[^]


ATeDe

Спасибо Мацей за ваше решение, которое, очевидно, работает хорошо, несмотря на небольшую "заминку" в начале, как мой VB.NET компилятор (VS2017) не любит 1-ю строку кода:

Dim lines() As String = File.ReadAllLines(CSVfile).ToList() жалуется
Ошибка BC30311 значение типа 'List(Of String)' не может быть преобразовано в 'String()'

После изменения на
Dim lines() As String = File.ReadAllLines(CSVfile) код выполняется плавно

Еще одна мысль, которую следует заметить, заключается в том, что преобразование моего CSV-файла занимает примерно на 10% больше времени (10 столбцов, 131745 записей)

Спасибо!


Исходное кодовое затраченное время: 3490.86 миллисекунд
->Неформатированная таблица: Count= 131745
A,B,C,D,E,F,G,H,I,J
2014,26,00001,1,01,900001,150,150,0,1412
2014,26,00001,1,01,905111,3500,3500,0,1412
2014,26,00001,1,01,907213,60,0,60,1412
2014,26,00002,1,01,900001,250,250,0,1827
..................

Новое время выполнения процедуры: 3763,66 миллисекунды
->Неформатированная таблица: Count= 131745
A,B,C,D,E,F,G,H,I,J
2014,26,00001,1,01,900001,150,150,0,1412
2014,26,00001,1,01,905111,3500,3500,0,1412
2014,26,00001,1,01,907213,60,0,60,1412
2014,26,00002,1,01,900001,250,250,0,1827
..................

Maciej Los

Прости, это моя вина. Моя первая идея состояла в том, чтобы получить строки в массиве строк, но позже я решил получить строки в списке. Я забыл изменить тип объявления переменной. Просто рремове ToList() метод и это должно быть работой. Примечание: Я написал его прямо из головы.
Овации,
Мацей

Karthik_Mahalingam

5

Maciej Los

Спасибо, Картик.