it-swarm.com.de

Bestimmen Sie die Anzahl der Zeilen in einer Textdatei

Gibt es eine einfache Möglichkeit, die Anzahl der Zeilen in einer Textdatei programmgesteuert zu ermitteln?

194
TK.

Ernsthaft verspätete Bearbeitung: Wenn Sie .NET 4.0 oder höher verwenden

Die File -Klasse hat eine neue ReadLines -Methode, die Zeilen träge aufzählt, anstatt sie alle gierig in ein Array wie ReadAllLines einzulesen. So können Sie jetzt sowohl Effizienz als auch Prägnanz in Bezug auf Folgendes sicherstellen:

var lineCount = File.ReadLines(@"C:\file.txt").Count();

Ursprüngliche Antwort

Wenn Sie sich nicht zu sehr mit Effizienz beschäftigen, können Sie einfach schreiben:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;

Für eine effizientere Methode können Sie Folgendes tun:

var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}

Bearbeiten: Bei Fragen zur Effizienz

Der Grund, warum ich sagte, der zweite sei effizienter, sei die Speichernutzung, nicht unbedingt die Geschwindigkeit. Der erste Befehl lädt den gesamten Inhalt der Datei in ein Array. Dies bedeutet, dass mindestens so viel Speicher zugewiesen werden muss wie die Größe der Datei. Die zweite Schleife durchläuft jeweils nur eine Zeile, sodass nie mehr als eine Zeile gleichzeitig Speicher zugewiesen werden muss. Dies ist für kleine Dateien nicht so wichtig, aber für größere Dateien kann es ein Problem sein (wenn Sie beispielsweise versuchen, die Anzahl der Zeilen in einer 4-GB-Datei auf einem 32-Bit-System zu ermitteln, auf dem einfach nicht genug vorhanden ist) Adressraum im Benutzermodus, um ein so großes Array zuzuweisen).

In Sachen Geschwindigkeit würde ich nicht erwarten, dass viel drin ist. Es ist möglich, dass ReadAllLines einige interne Optimierungen hat, aber auf der anderen Seite muss möglicherweise ein massiver Speicherblock zugewiesen werden. Ich vermute, dass ReadAllLines für kleine Dateien möglicherweise schneller ist, für große Dateien jedoch erheblich langsamer. Die einzige Möglichkeit, dies festzustellen, besteht darin, es mit einer Stoppuhr oder einem Code-Profiler zu messen.

374
Greg Beech

Das einfachste:

int lines = File.ReadAllLines("myfile").Length;
12
leppie

Dies würde weniger Speicherplatz verbrauchen, aber wahrscheinlich länger dauern

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();
8
benPearce

Wenn mit einfach gemeint ist eine Codezeile, die leicht zu entschlüsseln ist, aber per Zufall ineffizient?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();

Das ist wahrscheinlich der schnellste Weg, um zu wissen, wie viele Zeilen es gibt.

Das könnten Sie auch tun (je nachdem, ob Sie es in den Puffer legen)

#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}

Es gibt viele andere Möglichkeiten, aber eine der oben genannten ist wahrscheinlich die, mit der Sie gehen werden.

5
user8456

Sie können es schnell einlesen und einen Zähler inkrementieren. Verwenden Sie einfach eine Schleife, um den Wert zu erhöhen, und tun nichts mit dem Text.

2
Mitchel Sellers

Das Einlesen einer Datei an und für sich nimmt einige Zeit in Anspruch. Das Sammeln von Müll ist ein weiteres Problem, da Sie die gesamte Datei nur lesen, um die Zeilenumbruchzeichen zu zählen.

Irgendwann muss jemand die Zeichen in der Datei lesen, unabhängig davon, ob dies das Framework ist oder ob es sich um Ihren Code handelt. Dies bedeutet, dass Sie die Datei öffnen und in den Speicher lesen müssen, wenn die Datei groß ist. Dies kann möglicherweise ein Problem darstellen, da der Speicher müllsammelbar sein muss.

Nima Ara hat eine nette Analyse gemacht, die Sie in Betracht ziehen könnten

Hier ist die vorgeschlagene Lösung, da sie 4 Zeichen gleichzeitig liest, das Zeilenvorschubzeichen zählt und dieselbe Speicheradresse erneut für den nächsten Zeichenvergleich verwendet.

private const char CR = '\r';  
private const char LF = '\n';  
private const char NULL = (char)0;

public static long CountLinesMaybe(Stream stream)  
{
    Ensure.NotNull(stream, nameof(stream));

    var lineCount = 0L;

    var byteBuffer = new byte[1024 * 1024];
    const int BytesAtTheTime = 4;
    var detectedEOL = NULL;
    var currentChar = NULL;

    int bytesRead;
    while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
    {
        var i = 0;
        for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 1];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 2];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 3];
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
                i -= BytesAtTheTime - 1;
            }
        }

        for (; i < bytesRead; i++)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
            }
        }
    }

    if (currentChar != LF && currentChar != CR && currentChar != NULL)
    {
        lineCount++;
    }
    return lineCount;
}

Oben ist zu sehen, dass eine Zeile von dem zugrunde liegenden Framework jeweils einzeln gelesen wird, da Sie alle Zeichen lesen müssen, um den Zeilenvorschub zu sehen.

Wenn Sie es als erledigt bezeichnen, werden Sie feststellen, dass dies eine recht schnelle und effiziente Methode ist.

zeilenumbrüche/Zeilenvorschübe zählen. Ich glaube an Unicode, sie sind immer noch 0x000D und 0x000A. Auf diese Weise können Sie so effizient oder ineffizient sein, wie Sie möchten, und entscheiden, ob Sie mit beiden Charakteren umgehen müssen oder nicht

1
geocoin

Eine praktikable Option, die ich persönlich genutzt habe, wäre, der ersten Zeile der Datei einen eigenen Header hinzuzufügen. Ich habe dies für ein benutzerdefiniertes Modellformat für mein Spiel gemacht. Grundsätzlich habe ich ein Tool, das meine .obj-Dateien optimiert, den Mist beseitigt, den ich nicht benötige, sie in ein besseres Layout konvertiert und dann die Gesamtzahl der Linien, Flächen, Normalen, Scheitelpunkte und Textur-UVs aufschreibt die allererste Zeile. Diese Daten werden dann von verschiedenen Array-Puffern verwendet, wenn das Modell geladen wird.

Dies ist auch nützlich, da Sie die Datei nur einmal durchlaufen müssen, um sie zu laden, anstatt die Zeilen einmal zu zählen und die Daten erneut in die von Ihnen erstellten Puffer zu lesen.

1
Krythic