TextFieldParser 从字符串而不是文件解析 CSV
TextFieldParser parse CSV from string not file
使用 Microsoft.VisualBasic.FileIO 中的 TextFieldParser 可以像下面这样解析 CSV 文件:
using (TextFieldParser parser = new TextFieldParser(CSVPath))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData) { string[] fields = parser.ReadFields(); }
}
然而,这依赖于使用 CSV 文件路径初始化 TextFieldParser。是否可以在传递包含数据记录本身的字符串时产生相同的效果?
例如,在字符串变量中保存了一个值为 Data1,6.5,"Data3 ""MoreData"""
的 CSV 数据记录(请注意最后用引号引起来的数据,因为转义引号),我可以将数据转换为字符串吗像这样的数组:
[0] = "Data1"
[1] = "6.5"
[2] = "Data3 \"MoreData\""
您还可以从 Stream 或 TextReader 实例化 TextFieldParser。它不一定是字符串路径。所以,你可以随心所欲地流式传输它,只要你能将它放入流中即可。可以只是一个 MemoryStream。
例如
using (var stream = new MemoryStream())
{
var input = "A, B, C, D\r\n";
input += "Jeremy,Paul,Linda,Joe\r\n";
var bytes = System.Text.Encoding.Default.GetBytes(input);
stream.Write(bytes, 0, bytes.Length);
stream.Seek(0, SeekOrigin.Begin);
using (var parser = new TextFieldParser(stream))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
Console.WriteLine("Line:");
var fields = parser.ReadFields();
foreach (var field in fields)
{
Console.WriteLine("\tField: " + field);
}
}
}
}
可以将包含原始字符串的 StringReader 传递到新的 TextFieldParser 并以相同的方式进行处理。
StringReader sr = new StringReader("Data1,6.5,\"Data3,\"\"MoreData\"\"\"");
using (var parser = new TextFieldParser(sr))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
Console.WriteLine("Line:");
var fields = parser.ReadFields();
foreach (var field in fields)
{
Console.WriteLine("\tField: " + field);
}
}
}
输出到控制台:
Line:
Field: Data1
Field: 6.5
Field: Data3,"MoreData"
使用 TextFieldParser 是最简单的方法,正如接受的答案中所说,您完全可以从流中实例化它。
尽管如此,我还是想为所有通过 G**gle 搜索来到这里的人提供一条有价值的信息来完成已接受的答案:
我发现一个非常简单的解析器用这段代码读取 CSV 数据:
var res = new List<string[]>();
using (TextFieldParser parser = new TextFieldParser(filepath))
{
parser.CommentTokens = new string[] { "#" };
parser.SetDelimiters(new string[] { ";" });
parser.HasFieldsEnclosedInQuotes = true;
// Skip over header line.
parser.ReadLine();
while (!parser.EndOfData)
{
res.Add(parser.ReadFields());
}
}
请务必小心使用 parser.ReadLine(),因为如果您的 header 的至少一个字段包含 CRLF,它可能会产生不需要的结果。
在这种情况下,您的第一个阅读行将在第一个 CRLF 之后包含 header 的剩余部分。
所以请注意,使用 ReadFields 读取整个文件会更好,它会很好地处理格式正确的字段(参见 https://www.rfc-editor.org/rfc/rfc4180 的 CSV RFC),包括 headers ,然后在需要时忽略您的第一行。
4180 RFC 足够完整,如果您也想实现适当的 CSV 编写器,可以为您提供方法。
祝大家玩得开心。
使用 Microsoft.VisualBasic.FileIO 中的 TextFieldParser 可以像下面这样解析 CSV 文件:
using (TextFieldParser parser = new TextFieldParser(CSVPath))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData) { string[] fields = parser.ReadFields(); }
}
然而,这依赖于使用 CSV 文件路径初始化 TextFieldParser。是否可以在传递包含数据记录本身的字符串时产生相同的效果?
例如,在字符串变量中保存了一个值为 Data1,6.5,"Data3 ""MoreData"""
的 CSV 数据记录(请注意最后用引号引起来的数据,因为转义引号),我可以将数据转换为字符串吗像这样的数组:
[0] = "Data1"
[1] = "6.5"
[2] = "Data3 \"MoreData\""
您还可以从 Stream 或 TextReader 实例化 TextFieldParser。它不一定是字符串路径。所以,你可以随心所欲地流式传输它,只要你能将它放入流中即可。可以只是一个 MemoryStream。
例如
using (var stream = new MemoryStream())
{
var input = "A, B, C, D\r\n";
input += "Jeremy,Paul,Linda,Joe\r\n";
var bytes = System.Text.Encoding.Default.GetBytes(input);
stream.Write(bytes, 0, bytes.Length);
stream.Seek(0, SeekOrigin.Begin);
using (var parser = new TextFieldParser(stream))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
Console.WriteLine("Line:");
var fields = parser.ReadFields();
foreach (var field in fields)
{
Console.WriteLine("\tField: " + field);
}
}
}
}
可以将包含原始字符串的 StringReader 传递到新的 TextFieldParser 并以相同的方式进行处理。
StringReader sr = new StringReader("Data1,6.5,\"Data3,\"\"MoreData\"\"\"");
using (var parser = new TextFieldParser(sr))
{
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
Console.WriteLine("Line:");
var fields = parser.ReadFields();
foreach (var field in fields)
{
Console.WriteLine("\tField: " + field);
}
}
}
输出到控制台:
Line:
Field: Data1
Field: 6.5
Field: Data3,"MoreData"
使用 TextFieldParser 是最简单的方法,正如接受的答案中所说,您完全可以从流中实例化它。
尽管如此,我还是想为所有通过 G**gle 搜索来到这里的人提供一条有价值的信息来完成已接受的答案:
我发现一个非常简单的解析器用这段代码读取 CSV 数据:
var res = new List<string[]>();
using (TextFieldParser parser = new TextFieldParser(filepath))
{
parser.CommentTokens = new string[] { "#" };
parser.SetDelimiters(new string[] { ";" });
parser.HasFieldsEnclosedInQuotes = true;
// Skip over header line.
parser.ReadLine();
while (!parser.EndOfData)
{
res.Add(parser.ReadFields());
}
}
请务必小心使用 parser.ReadLine(),因为如果您的 header 的至少一个字段包含 CRLF,它可能会产生不需要的结果。 在这种情况下,您的第一个阅读行将在第一个 CRLF 之后包含 header 的剩余部分。
所以请注意,使用 ReadFields 读取整个文件会更好,它会很好地处理格式正确的字段(参见 https://www.rfc-editor.org/rfc/rfc4180 的 CSV RFC),包括 headers ,然后在需要时忽略您的第一行。
4180 RFC 足够完整,如果您也想实现适当的 CSV 编写器,可以为您提供方法。
祝大家玩得开心。