web-dev-qa-db-fra.com

Déterminer le nombre de lignes dans un fichier texte

Existe-t-il un moyen simple de déterminer par programme le nombre de lignes dans un fichier texte?

194
TK.

Édition sérieusement tardive: Si vous utilisez .NET 4.0 ou version ultérieure

La classe File a une nouvelle méthode ReadLines qui énumère paresseusement les lignes plutôt que de les lire avec avidité dans un tableau du type ReadAllLines. Alors maintenant, vous pouvez avoir à la fois efficacité et concision avec:

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

Réponse originale

Si l'efficacité ne vous préoccupe pas trop, vous pouvez simplement écrire:

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

Pour une méthode plus efficace, vous pouvez faire:

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

Edit: En réponse aux questions sur l'efficacité

La raison pour laquelle j'ai dit que la seconde était plus efficace concernait l'utilisation de la mémoire, pas nécessairement la vitesse. Le premier charge l'intégralité du contenu du fichier dans un tableau, ce qui signifie qu'il doit allouer au moins autant de mémoire que la taille du fichier. La seconde boucle simplement une ligne à la fois, de sorte qu'elle ne doit jamais allouer plus d'une mémoire à la fois. Ce n'est pas très important pour les petits fichiers, mais pour les gros fichiers, cela peut poser un problème (si vous essayez de trouver le nombre de lignes dans un fichier de 4 Go sur un système 32 bits, par exemple, où il n'y a tout simplement pas assez espace d'adressage en mode utilisateur pour allouer un tableau de cette taille).

En termes de vitesse, je ne m'attendrais pas à ce qu'il y en ait beaucoup. Il est possible que ReadAllLines dispose d’optimisations internes, mais d’un autre côté, il peut être nécessaire d’allouer une énorme quantité de mémoire. J'imagine que ReadAllLines pourrait être plus rapide pour les petits fichiers, mais beaucoup plus lente pour les gros fichiers; bien que la seule façon de le savoir serait de le mesurer avec un chronomètre ou un profileur de code.

374
Greg Beech

Le plus facile:

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

Cela utiliserait moins de mémoire, mais prendrait probablement plus de temps

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

Si par facile vous entendez des lignes de code faciles à déchiffrer mais par hasard inefficaces?

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

C'est probablement le moyen le plus rapide de savoir combien de lignes.

Vous pouvez également le faire (selon que vous le tamponniez)

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

Il existe de nombreuses autres façons, mais l'une des solutions ci-dessus est probablement celle avec laquelle vous irez.

5
user8456

Vous pouvez le lire rapidement et incrémenter un compteur. Utilisez simplement une boucle pour incrémenter, sans rien faire avec le texte.

2
Mitchel Sellers

La lecture d’un fichier en elle-même prend un certain temps. La récupération du résultat est un autre problème, car vous lisez tout le fichier pour compter les caractères de nouvelle ligne,

À un moment donné, quelqu'un va devoir lire les caractères du fichier, que ce soit le cadre ou s'il s'agit de votre code. Cela signifie que vous devez ouvrir le fichier et le lire en mémoire si le fichier est volumineux, cela risque de poser problème, car la mémoire doit être nettoyée.

Nima Ara a fait une analyse intéressante que vous pourriez prendre en considération

Voici la solution proposée, car il lit 4 caractères à la fois, compte le caractère de saut de ligne et réutilise la même adresse mémoire pour la prochaine comparaison de caractères.

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

Ci-dessus, vous pouvez voir qu'une ligne est lue caractère par caractère, ainsi que par le framework sous-jacent, car vous devez lire tous les caractères pour voir le saut de ligne.

Si vous décrivez que c’est fait Bay Nima, vous constaterez que c’est un moyen plutôt rapide et efficace de le faire.

compter les retours chariot/sauts de ligne. Je crois en unicode qu'ils sont toujours 0x000D et 0x000A respectivement. De cette façon, vous pouvez être aussi efficace ou aussi inefficace que vous le souhaitez et décider si vous devez ou non traiter les deux personnages.

1
geocoin

Une option viable, et que j'ai personnellement utilisée, serait d'ajouter votre propre en-tête à la première ligne du fichier. Je l'ai fait pour un format de modèle personnalisé pour mon jeu. En gros, j’ai un outil qui optimise mes fichiers .obj, élimine la merde dont je n’ai pas besoin, les convertit en une meilleure présentation, puis écrit le nombre total de lignes, faces, normales, sommets et UV de texture sur la toute première ligne. Ces données sont ensuite utilisées par divers tampons de tableau lors du chargement du modèle.

Cela est également utile car il vous suffit de parcourir le fichier une seule fois pour le charger, au lieu d’une fois de compter les lignes, puis de lire les données dans les tampons créés.

1
Krythic