首页 > 解决方案 > 将 CsvHelper 与流一起使用

问题描述

我正在尝试使用 CsvHelper 读取 CSV 文件并从中创建一个 DataTable。第一行将是提供列名的标题记录,但除此之外,文件的结构是未知的。如果我使用以下代码(取自 CsvHelper 的作者的示例),它可以工作。

using (var reader = new StreamReader("path\\to\\file.csv"))
using (var csv = new CsvReader(reader))
{
    // Do any configuration to `CsvReader` before creating CsvDataReader.
    using (var dr = new CsvDataReader(csv))
    {        
        var dt = new DataTable();
        dt.Load(dr);
    }
}

但是,如果我为 StreamReader 使用另一个构造函数,该构造函数将 Stream 作为参数而不是文件路径,则 CsvDataReader 的创建将失败,并显示错误消息“不支持同步读取”。

我尝试了 CsvHelper 的其他一些方法来尝试以不同的方式处理数据,但是每当通过传入 Stream 而不是文件路径创建 StreamReader 时,我都会遇到相同的错误。我开始怀疑真正的问题是否在于 StreamReader 的实现或 CsvHelper。在我的情况(Blazor Server 应用程序)中,传入 Stream 更有意义。有任何想法吗?

编辑:

我相信 David Specht 是正确的,因为我使用的特定流有一些独特之处。在进一步的测试中,我发现一些字符串确实有效。在出现错误的情况下,我正在使用 IFileListEntry.Data 流接口从 Steve Sanderson 的 BlazorInputFile 组件(在 GitHub 上)读取流。我怀疑它的实现中有一些东西会导致我遇到错误。如果是这种情况,那么解决方法将很有帮助。(也许从另一个流创建一个流以在异步和同步流之间切换?还不确定如何做到这一点,但我会试一试。)

标签: csvstreamstreamreaderblazorcsvhelper

解决方案


正如 David Specht 在他的回答中指出的那样,并且正如我在对原始问题的编辑中所指出的那样,它确实适用于某些 Streams。在下面的示例中,流的实现中的某些内容file.Data不能很好地与 一起工作CsvHelper,从而导致“不支持同步读取”错误。这个特定的流是Steve Sanderson 创建IFileListEntry.DataBlazorInputFile组件的一个实例,可在 GitHub 上找到。(总而言之,这个组件似乎工作得很好,记住我使用的是0.1.0-preview-00002版本,所以谢谢,史蒂夫!)

通过将流复制到使用问题的新流Stream.CopyToAsync(),问题就消失了。要记住的一个警告是,在此函数执行后,输入和输出流都将位于流的末尾。将用于创建的流CsvReader必须设置回开头,以便CsvDataReader构造函数正常工作。如果不这样做,将会出现“No header record was found”错误。

以下示例适用于我,并希望对其他人有所帮助!

using (var stream2 = new MemoryStream())
{
    await file.Data.CopyToAsync(stream2);   // although file.Data is itself a stream, using it directly causes "synchronous reads are not supported" errors below.
    stream2.Seek(0, SeekOrigin.Begin);      // at the end of the copy method, we are at the end of both the input and output stream and need to reset the one we want to work with.
    var reader = new System.IO.StreamReader(stream2);

    using (var csv = new CsvReader(reader))
    {
        using (var dr = new CsvDataReader(csv)) // error happens here when "file.Data" is used as the stream: "Synchronous reads are not supported"
                                                // error happens here when the stream isn't reset to the beginning: "No header record was found"
        {
            var dt = new DataTable();
            dt.Load(dr);
        }
    }
}

推荐阅读