读取文件的最后30,000行

如果有一个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中不存在

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

来自MSDN: File.ReadLines()

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

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

解决方案1

  string[] lines = File.ReadAllLines(FileName).Where(r => r.ToString() != "").ToArray(); int count = lines.Count(); List orderList = new List(); 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以来是可用的。

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

  List lines = new List(); List orderList = new List(); 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]); } 

您可以使用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 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(); 

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

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

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

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

或者我有一个不同的意识形态。

尝试将csv拆分为AD,EG等类别,并访问您需要的第一个字符。

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

Txt文件:

 entitesID | inWhich.Csv ....