首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用StreamReader和LINQ的CSV阅读器

使用StreamReader和LINQ的CSV阅读器
EN

Code Review用户
提问于 2014-09-04 20:28:23
回答 1查看 26.8K关注 0票数 12

主要是由于可读性,我使用以下代码

  1. 在驱动器上找到特定的csv文件
  2. 使用streamReader读取CSV文件
  3. 将其解析为List<string[]>,以便以后能够使用LINQ和/或PLINQ

然而,这个过程大约需要4-5秒,这只是简单地说太长了。关于如何改进以下内容(甚至可能替换它),有什么建议吗?

代码语言:javascript
复制
var query = (from x in Directory.GetFiles(_path, "*.csv").AsParallel()
                     where x.Contains(dateTime)
                     select x).First();


        #region Read CSV File
        List<string[]> _tempList = new List<string[]>();

        FileStream stream = new FileStream(query, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        using (StreamReader reader = new StreamReader(stream, Encoding.Default, true, 1024))
        {
            string currentLine;
            while ((currentLine = reader.ReadLine()) != null)
            {
                string[] temp = currentLine.Split(new char[] { ',' }, StringSplitOptions.None);
                _tempList.Add(temp);
            }
        }
        #endregion

CSV文件内的顺序很重要--该文件将包含(2000-7000) x25项之间的内容。

CSV文件有几个我不感兴趣的字段--我不一定需要它们在我的List<string[]> (或string[][])中。我尝试使用类似于以下伪代码的LINQ语句对它们进行筛选:

代码语言:javascript
复制
var query = from x in MyListOfStringArray
            select new {Col1 = x[1] , Col2 = c[4]}.ToArray();

这种方法导致了一种奇怪的查询类型--而且非常慢(我将有一个具有大约9-11属性的数组)。对第二个问题有什么想法吗?

EN

回答 1

Code Review用户

回答已采纳

发布于 2014-09-05 01:53:55

var query =( Directory.GetFiles(_path,“*.csv”)中的x).AsParallel(),其中x.Contains(dateTime)选择x).First();

如果Directory.GetFiles(_path, "*.csv")不返回任何文件( where x.Contains(dateTime) ),那么这一行就会被一个可能有点令人失望/令人惊讶的InvalidOperationException炸开。

我发现使用100%的方法语法可以更清楚地查询--这将是等价的:

代码语言:javascript
复制
var query = Directory.GetFiles(_path, "*.csv")
                     .AsParallel()
                     .Where(name => name.Contains(dateTime))
                     .First();

query这个名字是错误的/误导的。如果它是一个IQueryable<string> (即直到.Where()调用之后),这将是一个查询.但事实并非如此,var实际上代表string,您所称的query实际上是一个fileName.First()将查询物化,并返回第一个元素.或者抛出一个异常。

最好调用.FirstOrDefault(),如果没有符合搜索条件的文件,这将使结果null

我不明白您为什么在这里使用var,因为您在其他地方都使用显式类型。特别是因为var只是一个string。不过,别误会我:我更喜欢在这里看到var .还有其他地方。

#区域读取CSV文件

在方法中使用#region可以清楚地表示,您的方法正在做不止一件事情。每当你这样做的时候,你就错过了一个重构的机会。考虑在这里提取一种方法:

代码语言:javascript
复制
private string GetFileName(string formattedDateTime)
{
    return Directory.GetFiles(_path, "*.csv")
                    .AsParallel()
                    .Where(name => name.Contains(formattedDateTime))
                    .FirstOrDefault();
}

(缺乏推荐传入实际DateTime的上下文)

这就给您留下了一个方法(希望)现在只有这个#region块,它现在完全是多余的,可以被丢弃(如果还有更多的方法,请根据需要提取方法)。

上面说..。

FileStream stream =新FileStream(查询、FileMode.Open、FileAccess.Read、FileShare.ReadWrite);使用(StreamReader reader =新StreamReader(StreamReader,Encoding.Default,true,1024))

配置StreamReader也会干净地关闭和释放FileStream,但这还远远不是显而易见的,除非您知道这一点,并且如果乔恩·斯基特说这是最好的做法将它放在自己的using块中,那么我只能同意他的意见。

您的代码可以使用一个变量(在循环正文之外声明)作为值分隔符:您正在为正在读取的每一行创建一个新的字符数组!

代码语言:javascript
复制
char[] separator = new char[] { ',' };

或者更简洁地说:

代码语言:javascript
复制
var separator = new[] { ',' };

这使得temp分配更加清晰/更清晰:

代码语言:javascript
复制
string[] temp = currentLine.Split(separator, StringSplitOptions.None);

看看currentLine,我们还不清楚这里发生了什么:

代码语言:javascript
复制
while ((currentLine = reader.ReadLine()) != null)

使用赋值的结果很少会产生容易读的代码。我喜欢它如何巧妙地将下一行读入currentLine并验证它是否是null值.所以我不确定我是否会建议重写那部分。

当您阅读完文件时,还不清楚您的List<string[]>发生了什么,所以我假设您只是返回它。在这种情况下,您可以考虑使用yield来处理结果:

代码语言:javascript
复制
private IEnumerable<string[]> ReadCsv(string fileName)
{
    char[] separator = new[] { ',' };
    string currentLine;

    using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    using (var reader = new StreamReader(stream, Encoding.Default, true, 1024))
    {
        while ((currentLine = reader.ReadLine()) != null)
        {
            yield return currentLine.Split(separator, StringSplitOptions.None);
        }
    }
}
票数 9
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/61973

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档