Wie kann ich die Position (Zeilennummer) eines Streamreaders in einer Textdatei erkennen?

8

ein Beispiel (das ist vielleicht nicht das wirkliche Leben, aber um meinen Standpunkt zu verdeutlichen):

%Vor%

GetLinePosition ist hier eine imaginäre Erweiterungsmethode von streamreader. Ist das möglich?

Natürlich könnte ich mich selbst zählen, aber das ist nicht die Frage.

    
Peter 06.05.2009, 13:31
quelle

7 Antworten

7

Es ist sehr einfach, einen Wrapper mit Zeilenzählung für jeden TextReader bereitzustellen:

%Vor%

Nachteile (aus Gründen der Kürze):

  1. Überprüft das Konstruktorargument nicht auf null
  2. Keine alternativen Möglichkeiten zum Beenden der Zeilen erkannt. Wird beim Lesen von Dateien, die durch "raw" oder "n" getrennt sind, inkonsistent sein mit dem ReadLine () - Verhalten.
  3. überschreibt keine "block" -level-Methoden wie Read (char [], int, int), ReadBlock, ReadLine, ReadToEnd. Die TextReader-Implementierung funktioniert ordnungsgemäß, da sie alles andere an Read () weiterleitet. jedoch könnte eine bessere Leistung erreicht werden durch
    • überschreibt diese Methoden über Routing-Aufrufe an _inner. anstelle der Basis.
    • übergibt die gelesenen Zeichen an die AdvancePosition. Siehe die Beispiel-ReadBlock-Implementierung:
%Vor%     
Sinclair 16.01.2012, 07:18
quelle
13

Ich habe diesen Beitrag durchsucht, als ich nach einer Lösung für ein ähnliches Problem suchte, bei dem ich den StreamReader nach bestimmten Zeilen suchen musste. Am Ende habe ich zwei Erweiterungsmethoden erstellt, um die Position auf einem StreamReader zu erhalten und festzulegen. Es liefert eigentlich keine Zeilenzahl, aber in der Praxis nehme ich einfach die Position vor jeder ReadLine () und wenn die Zeile von Interesse ist, dann behalte ich die Startposition für die spätere Einstellung, um wie in der Zeile zurück zu kommen :

%Vor%

und der wichtige Teil:

%Vor%

Das funktioniert ganz gut für mich und hängt von Ihrer Toleranz für die Verwendung von Reflektion ab. Es ist eine ziemlich einfache Lösung.

Vorbehalte:

  1. Während ich einige einfache Tests mit verschiedenen System.Text.Encoding-Optionen durchgeführt habe, sind so ziemlich alle Daten, die ich damit konsumiere, einfache Textdateien (ASCII).
  2. Ich benutze immer nur die StreamReader.ReadLine () -Methode und während eine kurze Überprüfung der Quelle für StreamReader darauf hinweist, dass dies immer noch funktioniert, wenn ich die anderen Lesemethoden benutze, habe ich dieses Szenario nicht wirklich getestet.
Eamon 09.04.2014 23:10
quelle
10

Nein, nicht wirklich möglich. Das Konzept einer "Zeilennummer" basiert auf den tatsächlichen Daten, die bereits gelesen wurden, nicht nur auf der Position. Wenn Sie beispielsweise den Reader an einer beliebigen Position suchen, liest er diese Daten nicht wirklich, so dass er die Zeilennummer nicht ermitteln kann.

Der einzige Weg, dies zu tun, ist, es selbst zu verfolgen.

    
Adam Robinson 06.05.2009 13:36
quelle
4

Nein.

Beachten Sie, dass es möglich ist, mit dem zugrundeliegenden Stream-Objekt (das an irgendeinem Punkt in jeder Zeile sein könnte) nach einer Position zu suchen. Überlegen Sie sich nun, was das mit einem vom StreamReader gehaltenen Zählwert tun würde.

Sollte der StreamReader gehen und herausfinden, in welcher Zeile er jetzt ist? Soll es nur eine Reihe von Zeilen lesen, unabhängig von der Position in der Datei?

Es gibt mehr Fragen als nur diese, die dies zu einem Alptraum machen würden, imho.

    
Binary Worrier 06.05.2009 13:37
quelle
3

Hier ist ein Typ, der einen StreamReader mit der ReadLine () -Methode implementiert hat, der die Dateiposition registriert.

Ссылка

Ich denke, man sollte von StreamReader erben und dann die zusätzliche Methode der speziellen Klasse zusammen mit einigen Eigenschaften (_lineLength + _bytesRead) hinzufügen:

%Vor%

Denken Sie, es gibt einen kleineren Fehler im Code, da die Länge der Zeichenfolge zur Berechnung der Dateiposition verwendet wird, anstatt die tatsächlich gelesenen Bytes zu verwenden (fehlende Unterstützung für UTF8- und UTF16-codierte Dateien).

    
Rolf Kristensen 06.10.2010 07:59
quelle
3

Ich kam hierher, um nach etwas Einfachem zu suchen. Wenn Sie nur ReadLine () verwenden und Seek () oder irgendetwas anderes nicht verwenden möchten, erstellen Sie einfach eine einfache Unterklasse von StreamReader

%Vor%

und dann machen Sie es zum normalen Weg, sagen Sie von einem FileInfo-Objekt namens Datei

%Vor%

und Sie haben gerade die Eigenschaft reader.LineNumber gelesen.

    
Andy Hubbard 18.02.2014 23:00
quelle
1

Die bereits in Bezug auf den BaseStream gemachten Punkte sind gültig und wichtig. Es gibt jedoch Situationen, in denen Sie einen Text lesen und wissen möchten, wo im Text Sie sind. Es kann immer noch nützlich sein, dies als eine Klasse zu schreiben, um die Wiederverwendung zu erleichtern.

Ich habe jetzt versucht, eine solche Klasse zu schreiben. Es scheint richtig zu funktionieren, aber es ist ziemlich langsam. Es sollte in Ordnung sein, wenn die Leistung nicht entscheidend ist (es ist nicht das langsam, siehe unten).

Ich verwende dieselbe Logik, um die Position im Text zu verfolgen, unabhängig davon, ob Sie ein Zeichen zu einem Zeitpunkt, einen Puffer nach dem anderen oder eine Zeile nach der anderen lesen. Während ich sicher bin, dass dies durch das Aufgeben etwas besser gemacht werden kann, wurde es viel einfacher implementiert ... und ich hoffe, dass ich dem Code folgen kann.

Ich habe einen sehr grundlegenden Leistungsvergleich der ReadLine-Methode (die meiner Meinung nach der schwächste Punkt dieser Implementierung ist) mit StreamReader durchgeführt, und der Unterschied ist fast eine Größenordnung. Ich habe 22 MB / s mit meiner Klasse StreamReaderEx, aber fast 9-mal so viel mit StreamReader direkt (auf meinem mit SSD ausgestatteten Laptop). Obwohl es interessant sein könnte, weiß ich nicht, wie man einen richtigen Lesetest macht; vielleicht mit 2 identischen Dateien, jede größer als der Disk-Puffer, und sie abwechselnd lesen ..? Zumindest führt mein einfacher Test zu konsistenten Ergebnissen, wenn ich ihn mehrmals ausführe und unabhängig davon, welche Klasse die Testdatei zuerst liest.

Das NewLine-Symbol ist standardmäßig Environment.NewLine, kann aber auf eine beliebige Zeichenfolge der Länge 1 oder 2 gesetzt werden. Der Leser betrachtet nur dieses Symbol als Zeilenumbruch, was ein Nachteil sein kann. Zumindest weiß ich, dass Visual Studio mich ziemlich oft dazu aufgefordert hat, dass eine geöffnete Datei "inkonsistente Zeilenumbrüche" aufweist.

Bitte beachten Sie, dass ich die Guard-Klasse nicht eingeschlossen habe; Dies ist eine einfache Hilfsklasse, und es sollte aus dem Kontext ersichtlich sein, wie man sie ersetzt. Sie können es sogar entfernen, aber Sie würden einige Argumentüberprüfung verlieren und folglich würde der resultierende Code weiter vom "korrekten" sein. Zum Beispiel überprüft Guard.NotNull (s, "s") einfach, dass s nicht null ist, und wirft eine ArgumentNullException (mit dem Argumentnamen "s", daher der zweite Parameter), sollte es der Fall sein.

Genug geplappert, hier ist der Code:

%Vor%     
The Dag 23.01.2012 13:04
quelle

Tags und Links