Domanda

Esiste un modo semplice per determinare a livello di codice il numero di righe all'interno di un file di testo?

È stato utile?

Soluzione

Modifica seriamente tardiva: se si utilizza .NET 4.0 o versioni successive

La classe File ha un nuovo Metodo ReadLines che elenca pigramente le righe piuttosto che leggerle avidamente tutte in una matrice come ReadAllLines . Quindi ora puoi avere sia efficienza che concisione con:

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

Risposta originale

Se non ti preoccupi troppo dell'efficienza, puoi semplicemente scrivere:

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

Per un metodo più efficiente potresti fare:

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

Modifica: in risposta a domande sull'efficienza

Il motivo per cui ho detto che il secondo era più efficiente riguardava l'utilizzo della memoria, non necessariamente la velocità. Il primo carica l'intero contenuto del file in un array, il che significa che deve allocare almeno la quantità di memoria della dimensione del file. Il secondo esegue semplicemente il loop di una riga alla volta, quindi non deve mai allocare più di una riga di memoria alla volta. Questo non è così importante per file di piccole dimensioni, ma per file più grandi potrebbe essere un problema (se si tenta di trovare il numero di righe in un file da 4 GB su un sistema a 32 bit, ad esempio, dove semplicemente non è sufficiente spazio degli indirizzi in modalità utente per allocare un array così grande).

In termini di velocità, non mi aspetto che ci sia molto da fare. È possibile che ReadAllLines abbia alcune ottimizzazioni interne, ma d'altra parte potrebbe dover allocare un grosso pezzo di memoria. Immagino che ReadAllLines potrebbe essere più veloce per file piccoli, ma significativamente più lento per file di grandi dimensioni; sebbene l'unico modo per dirlo sarebbe misurarlo con un cronometro o un profiler di codice.

Altri suggerimenti

Il più semplice:

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

Questo richiederebbe meno memoria, ma probabilmente impiegherà più tempo

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

Se per facile intendi una riga di codice che è facile da decifrare ma per caso inefficiente?

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

Questo è probabilmente il modo più veloce per sapere quante righe.

Potresti anche farlo (a seconda se lo stai memorizzando nel buffer)

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

Ci sono altri numerosi modi, ma uno dei precedenti è probabilmente quello con cui andrai.

Potresti leggerlo rapidamente e incrementare un contatore, basta usare un ciclo per incrementare, senza fare nulla con il testo.

conta i ritorni a capo / avanzamenti riga. Credo che nell'unicode siano ancora rispettivamente 0x000D e 0x000A. in questo modo puoi essere efficiente o inefficiente quanto vuoi e decidere se devi avere a che fare con entrambi i personaggi oppure no

Un'opzione praticabile, e una che ho usato personalmente, sarebbe quella di aggiungere la propria intestazione alla prima riga del file. L'ho fatto per un formato modello personalizzato per il mio gioco. Fondamentalmente, ho uno strumento che ottimizza i miei file .obj, eliminando la merda di cui non ho bisogno, li converte in un layout migliore e quindi scrive il numero totale di linee, facce, normali, vertici e texture UV su la prima riga. Tali dati vengono quindi utilizzati da vari buffer di array quando viene caricato il modello.

Ciò è utile anche perché è necessario eseguire il ciclo del file solo una volta per caricarlo, anziché una volta per contare le righe e ancora per leggere i dati nei buffer creati.

La lettura di un file in sé e per sé richiede del tempo, la spazzatura che raccoglie il risultato è un altro problema mentre leggi l'intero file solo per contare i caratteri di nuova riga,

A un certo punto qualcuno dovrà leggere i caratteri nel file, indipendentemente dal fatto che si tratti del framework o del codice. Ciò significa che è necessario aprire il file e leggerlo in memoria se il file è grande, questo potrebbe essere potenzialmente un problema poiché la memoria deve essere raccolta in modo inutile.

Nima Ara ha fatto una bella analisi che potresti prendere in considerazione

Ecco la soluzione proposta, in quanto legge 4 caratteri alla volta, conta il carattere di avanzamento riga e riutilizza nuovamente lo stesso indirizzo di memoria per il successivo confronto di caratteri.

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

Sopra puoi vedere che una riga viene letta un carattere alla volta anche dal framework sottostante in quanto devi leggere tutti i caratteri per vedere il feed della riga.

Se lo profili come fatto Nima Bay vedresti che questo è un modo piuttosto veloce ed efficiente per farlo.

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

Puoi avviare il " wc .exe " eseguibile (viene fornito con UnixUtils e non necessita di installazione) eseguito come processo esterno. Supporta diversi metodi di conteggio delle righe (come unix vs mac vs windows).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top