Antworten:
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 auflistet, anstatt sie alle gierig in ein Array wie zu lesen ReadAllLines
. Jetzt können Sie sowohl Effizienz als auch Prägnanz erreichen mit:
var lineCount = File.ReadLines(@"C:\file.txt").Count();
Ursprüngliche Antwort
Wenn Sie sich nicht zu sehr um Effizienz kümmern, können Sie einfach schreiben:
var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
Für eine effizientere Methode könnten Sie Folgendes tun:
var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
while (reader.ReadLine() != null)
{
lineCount++;
}
}
Bearbeiten: Als Antwort auf Fragen zur Effizienz
Der Grund, warum ich sagte, dass der zweite effizienter war, war die Speichernutzung, nicht unbedingt die Geschwindigkeit. Der erste lädt den gesamten Inhalt der Datei in ein Array, was bedeutet, dass mindestens so viel Speicher wie die Größe der Datei zugewiesen werden muss. Die zweite Schleife führt jeweils nur eine Zeile durch, sodass nie mehr als eine Zeile Speicherplatz gleichzeitig 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 versuchen, die Anzahl der Zeilen in einer 4-GB-Datei auf einem 32-Bit-System zu ermitteln, wo beispielsweise einfach nicht genug vorhanden ist Adressraum im Benutzermodus, um ein so großes Array zuzuweisen).
In Bezug auf die Geschwindigkeit würde ich nicht erwarten, dass viel drin ist. Es ist möglich, dass ReadAllLines einige interne Optimierungen aufweist, andererseits muss möglicherweise ein großer Teil des Speichers zugewiesen werden. Ich würde vermuten, dass ReadAllLines für kleine Dateien schneller, für große Dateien jedoch erheblich langsamer ist. Die einzige Möglichkeit, dies festzustellen, besteht darin, es mit einer Stoppuhr oder einem Code-Profiler zu messen.
ReadLines().Count()
Sie using System.Linq
Ihren Includes ein hinzufügen . Es schien ziemlich unintuitiv zu sein, diesen Zusatz zu verlangen, deshalb erwähne ich ihn. Wenn Sie Visual Studio verwenden, wird dieser Zusatz wahrscheinlich automatisch für Sie ausgeführt.
Wenn mit einfach eine Codezeile gemeint ist, die leicht zu entschlüsseln, aber zufällig ineffizient ist?
string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();
Das ist wahrscheinlich der schnellste Weg, um zu wissen, wie viele Zeilen.
Sie können dies auch tun (je nachdem, ob Sie es einpuffern)
#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.
Sie können es schnell einlesen und einen Zähler erhöhen. Verwenden Sie einfach eine Schleife, um ihn zu erhöhen, und tun Sie nichts mit dem Text.
Das Einlesen einer Datei an und für sich dauert einige Zeit. Das Sammeln des Ergebnisses durch Müll ist ein weiteres Problem, da Sie die gesamte Datei lesen, um nur 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 Ihr Code ist. Dies bedeutet, dass Sie die Datei öffnen und in den Speicher einlesen müssen, wenn die Datei groß ist. Dies ist möglicherweise ein Problem, da der Speicher durch Müll gesammelt werden 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 für den nächsten Zeichenvergleich erneut 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 sehen Sie, dass eine Zeile auch vom zugrunde liegenden Framework zeichenweise gelesen wird, da Sie alle Zeichen lesen müssen, um den Zeilenvorschub zu sehen.
Wenn Sie es als erledigt in Bay Nima profilieren, werden Sie feststellen, dass dies eine ziemlich schnelle und effiziente Methode ist.
Eine praktikable Option, die ich persönlich verwendet habe, wäre das Hinzufügen eines eigenen Headers zur ersten Zeile der Datei. Ich habe dies für ein benutzerdefiniertes Modellformat für mein Spiel getan. Grundsätzlich habe ich ein Tool, das meine OBJ-Dateien optimiert, den nicht benötigten Mist beseitigt, 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 einmal, um die Zeilen zu zählen und die Daten erneut in Ihre erstellten Puffer einzulesen.
try {
string path = args[0];
FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
int i;
string s = "";
while ((i = fh.ReadByte()) != -1)
s = s + (char)i;
//its for reading number of paragraphs
int count = 0;
for (int j = 0; j < s.Length - 1; j++) {
if (s.Substring(j, 1) == "\n")
count++;
}
Console.WriteLine("The total searches were :" + count);
fh.Close();
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
Sie können die ausführbare Datei " wc .exe" (im Lieferumfang von UnixUtils enthalten und muss nicht installiert werden) als externen Prozess ausführen. Es unterstützt verschiedene Zeilenzählmethoden (wie Unix vs Mac vs Windows).