web-dev-qa-db-de.com

Wie lässt sich eine Datei am besten in die Liste <string> einlesen?

Ich verwende eine Liste, um die Dateigröße zu begrenzen, da das Ziel in der Festplatte und im RAM begrenzt ist.

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

Da logFile ein Array ist, können Sie es an den List<T>-Konstruktor übergeben. Dadurch wird unnötiger Overhead vermieden, wenn Sie das Array durchlaufen oder andere IO - Klassen verwenden.

Aktuelle Konstruktorimplementierung :

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;
            }
        }   
        ...
} 
92
Evan Mulawski

Ein kleines Update zu Evan Mulawskis Antwort, um es kürzer zu machen

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

47
Ram

Warum nicht stattdessen einen Generator verwenden?

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

Dann können Sie es wie eine Liste verwenden:

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

Wenn Sie einen List<string> benötigen, müssen Sie natürlich den gesamten Inhalt der Datei im Speicher behalten. Daran führt kein Weg vorbei.

12
Daniel Pryden

[Bearbeiten]

Wenn Sie dies tun, um den Anfang einer Protokolldatei zu beschneiden, können Sie das Laden der gesamten Datei vermeiden, indem Sie folgendermaßen vorgehen:

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

Da File.ReadAllLines die gesamte Datei in ein String-Array (string[]) lädt, ist das Kopieren in eine Liste überflüssig.

Zweitens müssen Sie verstehen, dass eine List unter Verwendung eines dynamischen Arrays unter der Haube implementiert wird. Dies bedeutet, dass CLR mehrere Arrays zuordnen und kopieren muss, bis die gesamte Datei gespeichert werden kann. Da sich die Datei bereits auf der Festplatte befindet, können Sie erwägen, die Arbeitsgeschwindigkeit für den Arbeitsspeicher zu ändern und die Festplattendaten direkt zu bearbeiten oder in kleineren Abschnitten zu verarbeiten.

  1. Wenn Sie es vollständig in den Speicher laden müssen, versuchen Sie mindestens, in einem Array zu bleiben:

     string[] lines = File.ReadAllLines("file.txt");
    
  2. Wenn es wirklich eine List sein muss, laden Sie die Zeilen einzeln:

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

    Hinweis: List<T> hat einen Konstruktor, der einen Kapazitätsparameter akzeptiert. Wenn Sie die Anzahl der Zeilen im Voraus kennen, können Sie Mehrfachzuweisungen verhindern, indem Sie das Array im Voraus vorbelegen:

     List<string> lines = new List<string>(NUMBER_OF_LINES);
    
  3. Umso besser, vermeiden Sie das Speichern der gesamten Datei und verarbeiten Sie sie "on the fly":

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

Bewahren Sie es möglichst nicht auf. Lesen Sie es einfach durch, wenn Sie an den Speicher gebunden sind. Sie können einen StreamReader verwenden:

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

Dies kann in eine Methode eingeschlossen werden, die Strings pro Zeile liefert, wenn Sie LINQ verwenden möchten.

4
Deleted
//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);
2
User2325641
List<string> lines = new List<string>();
 using (var sr = new StreamReader("file.txt"))
 {
      while (sr.Peek() >= 0)
          lines.Add(sr.ReadLine());
 }

ich würde dies vorschlagen ... von Groos Antwort.

1
user240141

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

Diese Antwort verfehlt den ursprünglichen Punkt, der besagt, dass sie einen OutOfMemory-Fehler erhalten haben. Wenn Sie mit der obigen Version fortfahren, werden Sie sicher darauf zugreifen, wenn Ihr System nicht über den geeigneten CONTIGUOUS-RAM zum Laden der Datei verfügt.

Sie müssen es einfach in Teile aufteilen und entweder als Liste oder als String [] speichern. 

0
RTZ ZZ

Sie können auf diese Weise einfach lesen. 

List<string> lines = System.IO.File.ReadLines(completePath).ToList();
0
string inLine = reader.ReadToEnd();
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();

Ich benutze auch Environment.NewLine.toCharArray, stellte jedoch fest, dass einige Dateien, die mit\r\n endeten, nicht funktionierten. Versuchen Sie es mit einem und ich hoffe, es funktioniert gut für Sie.

0
vSteve