将CsvHelper与流一起使用 [英] Using CsvHelper with a Stream

查看:142
本文介绍了将CsvHelper与流一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to use CsvHelper to read in a CSV file and create a DataTable from it. The first row will be a header record providing column names, but other than that, the structure of the file is unknown. If I use the following code (taken from an example by the author of CsvHelper), it works.

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的创建将失败,并显示错误消息不支持同步读取。

However, if I use an alternate constructor for the StreamReader that takes a Stream as a parameter instead of a file path, then the creation of the CsvDataReader fails with an error message of "Synchronous reads are not supported."

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

I've tried a few other methods of CsvHelper in attempts to handle the data differently, but I keep running into the same error any time that the StreamReader is created by passing in a Stream rather than a file path. I'm starting to wonder whether the real issue lies with the implementation of StreamReader or with CsvHelper. Passing in a Stream makes much more sense in my situation (a Blazor Server app). Any ideas?

编辑:

我相信David Specht是正确的,因为我当时所处的特定流有一些独特之处使用。在进一步的测试中,我发现某些字符串可以起作用。在出现错误的情况下,我正在使用IFileListEntry.Data流接口从Steve Sanderson的BlazorInputFile组件(在GitHub上)读取流。我怀疑其实施过程中会引起我遇到的错误。如果是这种情况,那么解决方法将很有帮助。 (也许是从另一个流创建一个流以在异步流和同步流之间切换?还不确定如何执行此操作,但是我要给它一个机会。)

I believe David Specht is correct in that there is something unique about the particular stream I was using. In further testing, I've found that some strings do work. In the situation where I have the error, I am reading the stream from Steve Sanderson's BlazorInputFile component (on GitHub) using the IFileListEntry.Data stream interface. I suspect that there is something in its implementation that causes the error I'm getting. If that's the case, then a workaround would be helpful. (Maybe creating one stream from another to switch between asynchronous and synchronous streams? Not sure how to do that yet, but I'm going to give it a shot.)

推荐答案

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

As David Specht pointed out in his answer, and as indicated in my edit to the original question, it does work with some Streams. Something in the implementation of the stream, file.Data, in the example below doesn't work well with CsvHelper, causing the "Synchronous reads are not supported" error. This particular stream is an instance IFileListEntry.Data from the BlazorInputFile component created by Steve Sanderson and available on GitHub. (All in all, this component seems to work quite well keeping in mind that I'm using version 0.1.0-preview-00002 so thanks, Steve!)

通过使用 Stream.CopyToAsync()将流复制到新流中,问题就解决了。需要牢记的一点是,执行此函数后,输入流和输出流都将位于流的末尾。必须将用于创建 CsvReader 的流重新设置为开始,以使 CsvDataReader 构造函数好好工作。如果不这样做,将出现找不到头记录错误。

By copying the stream to a new stream using Stream.CopyToAsync() the problem goes away. One caveat to keep in mind is that, after this function executes, both the input and output streams will be positioned at the end of the stream. The stream that will be used to create the CsvReader must be set back to the beginning in order for the CsvDataReader constructor to work properly. If this is not done, there will be a "No header record was found" error.

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

The following example works for me and will hopefully help someone else!

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);
        }
    }
}

这篇关于将CsvHelper与流一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆