2014-02-19 63 views
5

如果有一個csv文件,其數據會隨時增加。現在我需要做的是讀最後的30,000行。讀取文件的最後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。 .net 3.5中不存在Files.ReadLines()

+4

http://stackoverflow.com/questions/4619735/how-to-read-last-n-lines-of-log-file http://stackoverflow.com/questions/398378/get-last-10 - 超大文本文件-10gb -c-sharp/398512#398512 – Ofiris

回答

4

可以使用,而不是使用File.ReadAllLines()

從MSDN File.ReadLines()方法:File.ReadLines()

The ReadLines and 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()方法,因爲它是avaialble因爲.NET 4.0

可以使用的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]); 
     } 
+0

m使用.net 3.5。對不起,我忘了提到它 –

+0

@ShujaatSiddiqui:檢查我編輯的答案。 –

+0

@ShujaatSiddiqui:我認爲''ReadLines()'僅適用於.NET 4.0,您可以使用'StreamReader' –

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

'ReadAllLines'讀取所有行,如果文件很大,該怎麼辦? – Ofiris

+0

@Ofiris請參閱最新的帖子.. :) – Sachin

+0

m使用.net 3.5。對不起,我忘了提及它 –

0

或者我有一個不同的ideo。

嘗試將csv分割爲類似A-D,E-G .... 並存取您需要的第一個字符。

或者你也可以用entites計數來分割數據。例如,每個文件將包含15.000個實體。和文本文件,該文件將包含有關entits和位置像小數據:

TXT文件:

entitesID | inWhich.Csv 
.... 
1

的問題是,你不知道從哪裏開始讀文件,以獲得最後的30000行。除非要保持單獨的行偏移索引,否則您可以從僅保留最後30,000行的開始計數行讀取文件,也可以從結束計數行向後開始。如果文件非常大並且只需要幾行,最後一種方法可能很有效。然而,3似乎並不像「幾行」所以這裏是讀取從開始的文件,並使用隊列,以保持過去的30000行的方法:

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會將所有行一次拉入內存,可能會增加進程所需的內存。