2011-08-01 24 views
35

Tôi đang sử dụng danh sách để giới hạn kích thước tệp vì mục tiêu bị giới hạn trong đĩa và ram. Đây là những gì tôi đang làm bây giờ nhưng có cách nào hiệu quả hơn không?Cách tốt nhất để đọc một Tệp vào Danh sách <string>

readonly List<string> LogList = new List<string>(); 
... 
var logFile = File.ReadAllLines(LOG_PATH); 
foreach (var s in logFile) LogList.Add(s); 
+0

Sẽ không khó để thêm các mục vào 'LogList' khi bạn đã đánh dấu nó là 'readonly'? – Tim

+4

Điều đó có nghĩa là bạn không thể chỉ định lại tham chiếu thay vì đó là danh sách chỉ đọc. – Deleted

+0

Xin vui lòng không đặt "C#" trong tiêu đề của bạn chỉ để nói những gì câu hỏi là về - đó là những gì các thẻ được cho. –

Trả lời

75
var logFile = File.ReadAllLines(LOG_PATH); 
var logList = new List<string>(logFile); 

logFile là một mảng, bạn có thể chuyển nó tới hàm xây dựng List<T>. Điều này giúp loại bỏ chi phí không cần thiết khi lặp qua mảng, hoặc sử dụng các lớp IO khác.

Actual constructor implementation:

public List(IEnumerable<T> collection) 
{ 
     ... 
     ICollection<T> c = collection as ICollection<T>; 
     if(c != null) { 
      int count = c.Count; 
      if (count == 0) 
      { 
       _items = _emptyArray; 
      } 
      else { 
       _items = new T[count]; 
       c.CopyTo(_items, 0); 
       _size = count; 
      } 
     } 
     ... 
} 
+0

Cảm ơn một triệu. Tôi đã tìm ra một cách chính xác để làm điều này. – jacknad

5

Không lưu trữ nếu có thể. Chỉ cần đọc qua nó nếu bạn bị hạn chế về bộ nhớ. Bạn có thể sử dụng StreamReader:

using (var reader = new StreamReader("file.txt")) 
{ 
    var line = reader.ReadLine(); 
    // process line here 
} 

Điều này có thể được bao bọc trong một phương pháp tạo ra chuỗi trên mỗi dòng nếu bạn muốn sử dụng LINQ.

4

[Chỉnh sửa]

Nếu bạn đang làm điều này để cắt đầu của một tập tin nhật ký, bạn có thể tránh tải toàn bộ tập tin bằng cách làm một cái gì đó như thế này:

// count the number of lines in the file 
int count = 0; 
using (var sr = new StreamReader("file.txt")) 
{ 
    while (sr.ReadLine() != null) 
     count++; 
} 

// skip first (LOG_MAX - count) lines 
count = LOG_MAX - count; 
using (var sr = new StreamReader("file.txt")) 
using (var sw = new StreamWriter("output.txt")) 
{ 
    // skip several lines 
    while (count > 0 && sr.ReadLine() != null) 
     count--; 

    // continue copying 
    string line = ""; 
    while (line = sr.ReadLine() != null) 
     sw.WriteLine(line); 
} 

Đầu tiên, kể từ File.ReadAllLines tải toàn bộ tệp vào một mảng chuỗi (string[]), sao chép vào danh sách là không cần thiết.

Thứ hai, bạn phải hiểu rằng List được triển khai bằng cách sử dụng mảng động dưới mui xe. Điều này có nghĩa rằng CLR sẽ cần phải phân bổ và sao chép một số mảng cho đến khi nó có thể chứa toàn bộ tập tin. Kể từ khi tập tin đã có trên đĩa, bạn có thể xem xét tốc độ giao dịch cho bộ nhớ và làm việc trên đĩa dữ liệu trực tiếp, hoặc xử lý nó trong khối nhỏ hơn.

  1. Nếu bạn cần phải tải nó hoàn toàn trong bộ nhớ, ít nhất là cố gắng để lại trong một mảng:

    string[] lines = File.ReadAllLines("file.txt"); 
    
  2. Nếu nó thực sự cần là một List, đường dây tải từng người một:

    List<string> lines = new List<string>(); 
    using (var sr = new StreamReader("file.txt")) 
    { 
         while (sr.Peek() >= 0) 
          lines.Add(sr.ReadLine()); 
    } 
    

    Lưu ý:List<T> có hàm tạo chấp nhận tham số dung lượng. Nếu bạn biết số dòng trước, bạn có thể ngăn chặn nhiều phân bổ bởi preallocating mảng trước:

    List<string> lines = new List<string>(NUMBER_OF_LINES); 
    
  3. Thậm chí tốt hơn, tránh lưu trữ toàn bộ tập tin trong bộ nhớ và xử lý nó "on the fly":

    using (var sr = new StreamReader("file.txt")) 
    { 
         string line; 
         while (line = sr.ReadLine() != null) 
         { 
          // process the file line by line 
         } 
    } 
    
12

Tại sao không sử dụng máy phát điện?

private IEnumerable<string> ReadLogLines(string logPath) { 
    using(StreamReader reader = File.OpenText(logPath)) { 
     string line = ""; 
     while((line = reader.ReadLine()) != null) { 
      yield return line; 
     } 
    } 
} 

Sau đó, bạn có thể sử dụng nó như bạn sẽ sử dụng danh sách:

var logFile = ReadLogLines(LOG_PATH); 
foreach(var s in logFile) { 
    // Do whatever you need 
} 

Tất nhiên, nếu bạn cần phải có một List<string>, sau đó bạn sẽ cần phải giữ toàn bộ nội dung tập tin trong bộ nhớ. Thực sự không có cách nào xung quanh điều đó.

1
List<string> lines = new List<string>(); 
using (var sr = new StreamReader("file.txt")) 
{ 
     while (sr.Peek() >= 0) 
      lines.Add(sr.ReadLine()); 
} 

tôi sẽ đề xuất điều này ... của câu trả lời của Groo.

29

Một bản cập nhật nhỏ để Evan Mulawski câu trả lời để làm cho nó ngắn hơn

List<string> allLinesText = File.ReadAllLines(fileName).ToList()

+0

ý của bạn là evanBHOPS? – napi15

+0

Được sử dụng. +1 !! –

2
//this is only good in .NET 4 
//read your file: 
List<string> ReadFile = File.ReadAllLines(@"C:\TEMP\FILE.TXT").ToList(); 

//manipulate data here 
foreach(string line in ReadFile) 
{ 
    //do something here 
} 

//write back to your file: 
File.WriteAllLines(@"C:\TEMP\FILE2.TXT", ReadFile); 
+1

ReadFile không nên bắt đầu bằng số vốn – Chrotenise

0
string inLine = reader.ReadToEnd(); 
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList(); 

Tôi cũng sử dụng Environment.NewLine.toCharArray là tốt, nhưng không tìm thấy điều đó không làm việc trên một vài tệp đã kết thúc bằng \ r \ n. Hãy thử một trong hai và tôi hy vọng nó hoạt động tốt cho bạn.

+0

Chào mừng bạn đến với Stack Overflow! Các câu trả lời chỉ có mã được khuyến khích ở đây. Bạn có thể thêm một số giải thích về cách giải đáp tốt nhất câu hỏi này không? –

Các vấn đề liên quan