我在C#中使用VB的TextField来解析CSV文件。但是当它到达“
时我得到一个错误using (TextFieldParser csvReader = new TextFieldParser(csvFilePath)) {
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datacolumn = new DataColumn(column);
datacolumn.AllowDBNull = true;
csvData.Columns.Add(datacolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
这是导致错误的csv中的行:
"101","Brake System","Level should be between \"MIN\" and \"MAX\" marks."
我不知道如何使用TextFieldParser
来处理C#答案 0 :(得分:2)
如果csv文件适合内存,你可以读入它,用\"
替换每个""
,并使用MemoryStream作为TextFieldParser的输入:
string data = File.ReadAllText(@"C:\temp\csvdata.txt").Replace("\\\"", "\"\"");
//TODO: Use the correct Encoding.
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(data)))
{
using (TextFieldParser csvReader = new TextFieldParser(ms))
{
csvReader.SetDelimiters(new string[] { "," });
csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string s in colFields)
{
Console.WriteLine(s);
}
}
}
对于您的示例数据,输出
101
制动系统
等级应介于&#34; MIN&#34;和&#34; MAX&#34;标记。
答案 1 :(得分:0)
以下是使用两种不同方法而不使用TextFieldParser
的方法。 TextFieldParser
非常慢,不建议在实际的生产应用程序中使用。
以下是仅使用String
方法的简单方法,并假设它使用,
分隔,没有任何引号或任何其他特殊的CSV格式。
FileInfo file = new FileInfo("myfile.csv");
using (TextReader reader = file.OpenText())
{
for(String line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
string[] fields = line.Split(new[] {','});
foreach(String f in fields)
{
//do whatever you need for each field
}
}
}
现在,如果您想使用CsvHelper(在nuget上可用),那么您有一个更复杂的CSV文件,其中包含引号字段,标题或者CSV行可以直接映射到您的对象那么这个图书馆可能对你有帮助。
未映射示例:
FileInfo file = new FileInfo("myfile.csv");
using (TextReader reader = file.OpenText())
using (CsvReader csv = new CsvReader(reader))
{
csv.Configuration.Delimiter = ",";
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.IgnoreQuotes = true; //if you don't use field quoting
csv.Configuration.TrimFields = true; //trim fields as you read them
csv.Configuration.WillThrowOnMissingField = false; //otherwise null fields aren't allowed
while(csv.Read())
{
myStringVar = csv.GetField<string>(0); //gets first field as string
myIntVar = csv.GetField<int>(1); //gets second field as int
... //etc, you get the idea
}
}
映射示例:
映射类 - 假设您有一个名为MyClass
的类,其字段名为field1,field2,field3
public sealed class MyClassMap : CsvClassMap<MyClass>
{
public MyClassMap()
{
Map(m => m.field1).Index(0);
Map(m => m.field2).Index(1);
Map(m => m.field3).Index(2);
}
}
解析代码
FileInfo file = new FileInfo("myfile.csv");
using (TextReader reader = file.OpenText())
using (CsvReader csv = new CsvReader(reader))
{
csv.Configuration.Delimiter = ",";
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.IgnoreQuotes = true; //if you don't use field quoting
csv.Configuration.TrimFields = true; //trim fields as you read them
csv.Configuration.WillThrowOnMissingField = false; //otherwise null fields aren't allowed
csv.Configuration.RegisterClassMap<MyClassMap>(); //adds our mapping class to the reader
while(csv.Read())
{
myObject = csv.GetRecord<MyClass>();
//do whatever here
}
}
这两种方法都不会在乎你的csv文件中有\
这样的奇怪字符。
免责声明:我与CsvHelper没有任何关系,但过去在一些项目中取得了成功,使我的生活变得更加轻松
答案 2 :(得分:0)
如果您不介意使用其他库,Ctl.Data有一种模式(parseMidQuotes: true
)专门用于解析像这样的损坏的CSV。
using (StreamReader sr = new StreamReader("data.csv"))
{
var reader = new CsvReader<Record>(sr, parseMidQuotes: true, readHeader: false);
while (reader.Read())
{
Record rec = reader.CurrentObject.Value;
rec.Description = rec.Description.Replace("\\\"", "\"");
// use record...
}
}
定义您的Record
对象:
(通常它会将文件的标题与属性相匹配,但在您使用无标题文件的情况下,您需要使用Column
属性指定顺序。
class Record
{
[Column(Order = 0)]
public int Id { get; set; }
[Column(Order = 1)]
public string Category { get; set; }
[Column(Order = 2)]
public string Description { get; set; }
}
(免责声明:我是该图书馆的作者)