Как лучше всего прочитать файл в список <string> - PullRequest
48 голосов
/ 02 августа 2011

Я использую список для ограничения размера файла, так как цель ограничена на диске и оперативной памяти.Это то, что я делаю сейчас, но есть ли более эффективный способ?

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

Ответы [ 10 ]

96 голосов
/ 02 августа 2011
var logFile = File.ReadAllLines(LOG_PATH);
var logList = new List<string>(logFile);

Поскольку logFile - это массив, вы можете передать его конструктору List<T>. Это устраняет ненужные издержки при итерации по массиву или при использовании других классов ввода-вывода.

Реальная реализация конструктора :

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;
            }
        }   
        ...
} 
47 голосов
/ 25 мая 2012

Небольшое обновление ответа Эвана Мулавски, чтобы сделать его короче

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

13 голосов
/ 02 августа 2011

Почему бы не использовать генератор вместо этого?

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

Тогда вы можете использовать его, как если бы вы использовали список:

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

Конечно, если вам нужно иметь1007 *, тогда вам нужно будет сохранить все содержимое файла в памяти.Там действительно нет пути.

5 голосов
/ 02 августа 2011

[Редактировать]

Если вы делаете это, чтобы обрезать начало файла журнала, вы можете избежать загрузки всего файла, выполнив что-то вроде этого:

// 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);
}

Прежде всего, поскольку File.ReadAllLines загружает весь файл в массив строк (string[]), копирование в список является избыточным.

Во-вторых, вы должны понимать, что List реализован с использованием динамического массива под капотом.Это означает, что CLR потребуется выделить и скопировать несколько массивов, пока он не сможет вместить весь файл.Поскольку файл уже находится на диске, вы можете подумать о скорости обмена для памяти и непосредственной работе с данными на диске, или обрабатывать его небольшими кусками.

  1. Если вам необходимо полностью загрузить его в память, по крайней мере, попытайтесь оставить в массиве:

     string[] lines = File.ReadAllLines("file.txt");
    
  2. Если это действительно должно быть List, загрузите строки одну за другой:

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

    Примечание: List<T> имеет конструктор, который принимает параметр емкости.Если вы знаете количество строк заранее, вы можете предотвратить многократное выделение, предварительно выделив массив:

     List<string> lines = new List<string>(NUMBER_OF_LINES);
    
  3. Еще лучше, избегайте сохранения всего файла в памяти и обрабатывайте его"на лету":

     using (var sr = new StreamReader("file.txt"))
     {
          string line;
          while (line = sr.ReadLine() != null) 
          {
              // process the file line by line
          }
     }
    
4 голосов
/ 02 августа 2011

Не храните его, если это возможно.Просто прочитайте его, если у вас ограниченная память.Вы можете использовать StreamReader:

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

. Это может быть заключено в метод, который выдает строки на чтение строки, если вы хотите использовать LINQ.

2 голосов
/ 14 августа 2013
//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 голос
/ 31 января 2019

Вы можете просто прочитать этот путь.

List<string> lines = System.IO.File.ReadLines(completePath).ToList();
1 голос
/ 02 августа 2011
List<string> lines = new List<string>();
 using (var sr = new StreamReader("file.txt"))
 {
      while (sr.Peek() >= 0)
          lines.Add(sr.ReadLine());
 }

Я бы предложил это ... из ответа Гроо.

0 голосов
/ 21 декабря 2018

string inLine = reader.ReadToEnd ();myList = inLine.Split (новая строка [] {"\ r \ n"}, StringSplitOptions.None) .ToList ();

В этом ответе пропущена исходная точка, которая заключалась в том, что они получали ошибку OutOfMemory,Если вы продолжите работу с вышеприведенной версией, вы обязательно нажмете ее, если в вашей системе нет соответствующего НЕПРЕРЫВНОГО доступного ОЗУ для загрузки файла.

Вы просто должны разбить его на части и сохранить как список илиСтрока [] в любом случае.

0 голосов
/ 18 сентября 2015
string inLine = reader.ReadToEnd();
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();

Я также использую Environment.NewLine.toCharArray, но обнаружил, что он не работает с парой файлов, которые заканчиваются на \ r \ n. Попробуйте любой из них, и я надеюсь, что он вам подходит.

...