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。

https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.fileio.textfieldparser%28v=vs.110%29.aspx

例如

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 编写器,可以为您提供方法。

祝大家玩得开心。