读取文件的最后30,000行

时间:2014-02-19 07:19:20

标签: c# csv file-io

如果有一个csv文件,其数据会不时增加。现在我需要做的是阅读最后30,000行。

代码:

string[] lines = File.ReadAllLines(Filename).Where(r => r.ToString() != "").ToArray();

 int count = lines.Count();

 int loopCount = count > 30000 ? count - 30000 : 0;

  for (int i = loopCount; i < lines.Count(); i++)
  {
      string[] columns = lines[i].Split(',');
      orderList.Add(columns[2]);
  }

工作正常,但问题是

File.ReadAllLines(Filename)

阅读导致性能不足的完整文件。我想要的东西只能读取最后30,000行迭代整个文件。

PS:我正在使用.Net 3.5。 Files.ReadLines()不存在于.Net 3.5

4 个答案:

答案 0 :(得分:4)

您可以使用File.ReadLines()方法而不是File.ReadAllLines()

来自MSDN:File.ReadLines()

  

ReadLines ReadAllLines 方法的不同之处如下:
  使用ReadLines时,可以先开始枚举字符串集合   整个系列归还;当你使用ReadAllLines时,你必须   在您可以访问之前等待返回整个字符串数组   数组。

     

因此,当您使用非常大的文件时,    ReadLines 可以提高效率。

解决方案1 ​​

        string[] lines = File.ReadAllLines(FileName).Where(r => r.ToString() != "").ToArray();

        int count = lines.Count();
        List<String> orderList = new List<String>();
        int loopCount = count > 30000 ? 30000 : 0;

        for (int i = count-1; i > loopCount; i--)
        {
            string[] columns = lines[i].Split(',');
            orderList.Add(columns[2]);
        }

解决方案2:如果您正在使用.NET Framework 3.5,如下面的评论中所述,您不能使用File.ReadLines()方法,因为它是.NET 4.0以后的。{ / p>

您可以使用StreamReader,如下所示:

        List<string> lines = new List<string>();
        List<String> orderList = new List<String>();
        String line;
        int count=0;
        using (StreamReader reader = new StreamReader("c:\\Bethlehem-Deployment.txt"))
        {
            while ((line = reader.ReadLine()) != null)
            {
                lines.Add(line);
                count++;
            }
        }

        int loopCount = (count > 30000) ? 30000 : 0;

        for (int i = count-1; i > loopCount; i--)
        {
            string[] columns = lines[i].Split(',');
            orderList.Add(columns[0]);
        }

答案 1 :(得分:2)

您可以使用File.ReadLines,因为您可以在返回整个集合之前开始枚举字符串集合。

之后,您可以使用linq让事情变得更加轻松。 Reverse将颠倒收集顺序,Take将采用n个项目。现在再次添加Reverse以获取原始格式的最后n行。

var lines = File.ReadLines(Filename).Reverse().Take(30000).Reverse();

如果您使用的是.NET 3.5或更早版本,则可以创建自己的方法,其工作方式与File.ReadLines相同。以下是@Jon

最初编写的方法的代码
public IEnumerable<string> ReadLines(string file)
{
   using (TextReader reader = File.OpenText(file))
   {
      string line;
      while ((line = reader.ReadLine()) != null)
      {
         yield return line;
      }
   }
}

现在你可以使用linq来完成这个函数,就像上面的语句一样。

var lines = ReadLines(Filename).Reverse().Take(30000).Reverse();

答案 2 :(得分:1)

问题在于您不知道从哪里开始读取文件以获取最后30,000行。除非您想要保持单独的线偏移索引,否则您可以从开始计数行读取文件,仅保留最后30,000行,或者您可以从末尾计数行向后开始。如果文件非常大并且您只需要几行,则最后一种方法可以有效。但是,30,000似乎不是“几行”所以这里是一种从一开始就读取文件并使用队列来保留最后30,000行的方法:

var filename = @" ... ";
var linesToRead = 30000;
var queue = new Queue<String>();
using (var streamReader = File.OpenText(fileName)) {
  while (!streamReader.EndOfStream) {
    queue.Enqueue(streamReader.ReadLine());
    if (queue.Count > linesToRead)
      queue.Dequeue();
  }
}

现在您可以访问queue中存储的行。此类实现IEnumerable<String>,允许您使用foreach来迭代这些行。但是,如果您想要随机访问,则必须使用ToArray方法将队列转换为数组,这会给计算增加一些开销。

此解决方案在内存方面效率很高,因为最多需要将30,000行保留在内存中,垃圾收集器可以在需要时释放任何额外的行。使用File.ReadAllLines会立即将所有行拉入内存,这可能会增加进程所需的内存。

答案 3 :(得分:0)

或者我对此有不同的想法。

尝试将csv拆分为A-D,E-G等类别.... 并获取您需要的第一个字符。

或者您可以使用entites分数来分割数据。例如,每个文件将包含15.000个entites。还有一个文本文件,其中包含有关入侵和位置的微小数据,如:

Txt文件:

entitesID | inWhich.Csv
....