我正在尝试使用以下代码将CSV文件读入我的VB.net应用程序:
While Not EOF(1)
Input(1, dummy)
Input(1, phone_number)
Input(1, username)
Input(1, product_name)
Input(1, wholesale_cost)
Input(1, dummy)
Input(1, dummy)
End While
我的CSV文件(如文字)如下所示:
Customer Name,Phone Number,Username,Product,Wholesale Cost,Sales Price,Gross Profit, Customer Reference
,00000000000,00000000000,Product Name,25.00,35.00,10.00,
,00000000000,00000000000,Product Name,1.00,1.40,0.40,
如您所见,并非所有字段都包含在内,因此在读取文件时会显示错误,因为它无法到达行尾。
我该如何处理这类文件?
有时字段会在某些行上显示,而其他字段则不存在。
更新
我已经尝试了 Zenacity 提供的答案,但在尝试使用循环内的sArray(1)
进行阅读时,它会返回Index was outside the bounds of the array
答案 0 :(得分:11)
您应该掌握的一点是,Filexxxx
方法只是正式和正式弃用。使用它们时,Intellisense弹出:
...我的功能为您提供了比FileOpen更高的文件I / O操作的生产力和性能。有关更多信息,请参阅Microsoft.VisualBasic.FileIO.FileSystem。
他们在讨论My.Computer.FileSystem
但是有一些更有用的.NET方法。
帖子没有透露数据将如何存储,但如果它是任何种类和/或结构的数组,那么如果不过时则至少是次优的。这会将它存储在一个类中,以便数字数据可以存储为数字,并使用List
代替数组。
我使用一些随机数据制作了一个类似于你的快速文件:{"CustName", "Phone", "UserName", "Product", "Cost", "Price", "Profit", "SaleDate", "RefCode"}
:
Ziggy Aurantium,132-5562 ,, Cat Food,8.26,9.95,1.69,08 / 04/2016,
Catrina Caison,899-8599,Knife Sharpener,4.95,6.68,1.73,10 / 12/2016,X-873-W3
,784-4182 ,,蒸汽压缩机,11.02,12.53,1.51,09 / 12/2016,
注意:这是一种解析CSV的错误方法。这样做有很多问题可以解决;加上需要更多代码。它的呈现是因为它是一种不必处理缺失字段的简单方法。请参阅正确方法
' form/class level var:
Private SalesItems As List(Of SaleItem)
SaleItem
是一个存储您关注的元素的简单类。 SalesItems
是一个可以存储仅 SaleItem
个对象的集合。该类中的属性允许将价格和费用存储为Decimal
,将日期存储为DateTime
。
' temp var
Dim item As SaleItem
' create the collection
SalesItems = New List(Of SaleItem)
' load the data....all of it
Dim data = File.ReadAllLines("C:\Temp\custdata.csv")
' parse data lines
' Start at 1 to skip a Header
For n As Int32 = 0 To data.Length - 1
Dim split = data(n).Split(","c)
' check if it is a good line
If split.Length = 9 Then
' create a new item
item = New SaleItem
' store SOME data to it
item.CustName = split(0)
item.Phone = split(1)
' dont care anout user name (2)
item.Product = split(3)
' convert numbers
item.Price = Convert.ToDecimal(split(4))
item.Cost = Convert.ToDecimal(split(5))
' dont use the PROFIT, calculate it in the class (6)
' convert date
item.SaleDate = Convert.ToDateTime(split(7))
' ignore nonexistant RefCode (8)
' add new item to collection
' a List sizes itself as needed!
SalesItems.Add(item)
Else
' To Do: make note of a bad line format
End If
Next
' show in DGV for approval/debugging
dgvMem.DataSource = SalesItems
备注强>
存储可以简单计算的东西通常是个坏主意。所以Profit
属性是:
Public ReadOnly Property Profit As Decimal
Get
Return (Cost - Price)
End Get
End Property
如果更新成本或价格,它永远不会“陈旧”。
如图所示,使用生成的集合可以非常容易地显示给用户。给定DataSource
,DataGridView
将创建列并填充行。
String.Split(c)
是一个非常糟糕的主意,因为如果产品是:"Hose, Small Green"
,它会将其删除并将其视为2个字段。有许多工具可以为您完成几乎所有的工作:
除了课程外,上述所有内容都可以使用 CSVHelper 在几行内完成:
Private CustData As List(Of SaleItem)
...
Using sr As New StreamReader("C:\Temp\custdata.csv", False),
csv = New CsvReader(sr)
csv.Configuration.HasHeaderRecord = True
CustData = csv.GetRecords(Of SaleItem)().ToList()
End Using
两行或三行代码,用于读取,解析和创建250个项目的集合。
出于某种原因,即使你想手动,CSVHelper也可以提供帮助。您可以使用它来读取和解析数据,而不是为您创建List(Of SaleItem)
:
... like above
csv.Configuration.HasHeaderRecord = True
Do Until csv.Read() = False
For n As Int32 = 0 To csv.Parser.FieldCount - 1
DoSomethingWith(csv.GetField(n))
Next
Loop
这会逐一将字段返回给您。它不会转换任何日期或价格,但它也不会扼杀丢失的数据元素。
资源
答案 1 :(得分:5)
警告:如果CustomerName
或ProductName
值可以包含逗号' s
(。即CustomerName = "Callaway , Mark"
)您无法使用String.Split()
方法。并且最好搜索第三方csv解析器,或者你可以使用TextFieldParser
Class - > MSDN article
您可以点击此链接了解使用TextFieldParser
之前我遇到使用SQL Server Integration Services导入Csv文件时出现问题(字段包含分隔符),您可以查看一下(代码在Vb.net中):
Import CSV File Error : Column Value containing column delimiter
我的回答是假设缺少的字段始终位于该行的右侧,且字段值不包含逗号 (否则@Plutonix答案为你在寻找什么)
使用此代码,您可以导入缺少字段的行。
您必须从csv文件中读取每一行,使用以下代码计算此行中的","
出现次数
Line.Count(Function(c As Char) c = ",")
如果小于7
(8列),您将添加缺失的","
String.PadRight((7 - intCommaCount), ",")
注意: 如果缺少逗号来自左侧,则可以使用String.PadLeft((7 - intCommaCount), ",")
将该行拆分为Item属性
我创建了以下Item
类
Public Class MyItem
Public Property CustomerName As String
Public Property PhoneNumber As String
Public Property Username As String
Public Property Product As String
Public Property WholesaleCost As String
Public Property SalesPrice As String
Public Property GrossProfit As String
Public Property CustomerReference As String
Public Shared Function CreateObjectFromLine(ByVal Line As String) As MyItem
'Count Comma occurence in Line
Dim intCommaCount As Integer = Line.Count(Function(c As Char) c = CChar(","))
Dim strTemp = Line
'Add missing comma's
If intCommaCount < 7 Then
strTemp = strTemp.PadRight((7 - intCommaCount), ",")
End If
'Split Line and return MyItem Class
Dim str() As String = strTemp.Split(",")
Return New MyItem With {.CustomerName = str(0),
.PhoneNumber = str(1),
.Username = str(2),
.Product = str(3),
.WholesaleCost = str(4),
.SalesPrice = str(5),
.GrossProfit = str(6),
.CustomerReference = str(7)}
End Function
End Class
我使用以下代码从CSV文件导入数据
Dim SalesItems As New List(Of MyItem)
Dim csvFile As String = "C:\1.csv"
Using csvStreamReader As New IO.StreamReader(csvFile)
While Not csvStreamReader.EndOfStream
Dim strLine as string = csvStreamReader.ReadLine
' Skip Header
If strLine.StartsWith("Customer Name") Then Continue While
Dim item As MyItem = MyItem.CreateObjectFromLine(strLine)
SalesItems.Add(item)
End While
End Using
'Showing Result in a DataGridView
dgvItems.DataSource = SalesItems
注意: 这是一个简单的示例,需要添加错误处理Try... Catch
,Null
正在检查
答案 2 :(得分:4)
通过使用以下函数,您可以逐行评估文件内容并执行相应的操作。
Imports System.IO
Private Sub ParseCSVFile(psFile As String)
Dim sArray() As String
Dim Customer_Name As String = String.Empty
Dim Phone_Number As String = String.Empty
Dim Username As String = String.Empty
Dim Product As String = String.Empty
Dim Wholesale_Cost As String = String.Empty
Dim Sales_Price As String = String.Empty
Dim Gross_Profit As String = String.Empty
Dim Customer_Reference As String = String.Empty
Try
Using objStreamReader As StreamReader = New StreamReader(psFile) 'should be full path
Dim sLine As String = String.Empty
Do
sLine = objStreamReader.ReadLine()
If sLine <> Nothing Then
sArray = Split(sLine, ",")
Customer_Name = sArray(0)
Phone_Number = sArray(1)
Username = sArray(2)
Product = sArray(3)
Wholesale_Cost = sArray(4)
Sales_Price = sArray(5)
Gross_Profit = sArray(6)
Customer_Reference = sArray(7)
Debug.Print(Customer_Name & "," & Phone_Number & "," & Username & "," & Product & "," & Wholesale_Cost & "," & Sales_Price & "," & Gross_Profit & "," & Customer_Reference)
End If
Loop Until sLine Is Nothing
End Using
Catch
'log error
End Try
End Sub