397 votes

Quel est le moyen le plus rapide de lire un fichier texte ligne par ligne ?

Je veux lire un fichier texte ligne par ligne. Je voulais savoir si je le faisais aussi efficacement que possible dans le cadre de .NET C#.

C'est ce que j'ai essayé jusqu'à présent :

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}

11 votes

Par Fastest vous voulez dire du point de vue de la performance ou du développement ?

1 votes

Cela va verrouiller le fichier pour la durée de la méthode. Vous pourriez utiliser File.ReadAllLines dans un tableau, puis traiter ce tableau.

19 votes

BTW, joignez filestream = new FileStream en using() afin d'éviter d'éventuels problèmes de verrouillage des fichiers.

414voto

Martin Liversage Points 43712

Pour trouver le moyen le plus rapide de lire un fichier ligne par ligne, vous devrez procéder à une analyse comparative. J'ai fait quelques petits tests sur mon ordinateur mais vous ne pouvez pas vous attendre à ce que mes résultats s'appliquent à votre environnement.

Utilisation de StreamReader.ReadLine

C'est en gros votre méthode. Pour une raison quelconque, vous avez fixé la taille du tampon à la plus petite valeur possible (128). Augmenter cette valeur permet en général d'améliorer les performances. La taille par défaut est de 1 024 et d'autres bons choix sont 512 (la taille du secteur dans Windows) ou 4 096 (la taille du cluster dans NTFS). Vous devrez exécuter un benchmark pour déterminer la taille optimale de la mémoire tampon. Un tampon plus grand est, sinon plus rapide, du moins moins moins lent qu'un tampon plus petit.

const Int32 BufferSize = 128;
using (var fileStream = File.OpenRead(fileName))
  using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize)) {
    String line;
    while ((line = streamReader.ReadLine()) != null)
      // Process line
  }

Le site FileStream vous permet de spécifier Options de fichier . Par exemple, si vous lisez un fichier volumineux de manière séquentielle du début à la fin, vous pouvez bénéficier des avantages suivants FileOptions.SequentialScan . Encore une fois, l'analyse comparative est la meilleure chose que vous puissiez faire.

Utilisation de File.ReadLines

Cette solution est très proche de la vôtre, sauf qu'elle est mise en œuvre à l'aide d'une StreamReader avec une taille de tampon fixe de 1 024. Sur mon ordinateur, les performances sont légèrement meilleures que celles de votre code avec une taille de tampon de 128. Cependant, vous pouvez obtenir la même augmentation des performances en utilisant une taille de tampon plus importante. Cette méthode est mise en œuvre en utilisant un bloc d'itérateurs et ne consomme pas de mémoire pour toutes les lignes.

var lines = File.ReadLines(fileName);
foreach (var line in lines)
  // Process line

Utilisation de File.ReadAllLines

Cette méthode ressemble beaucoup à la précédente, sauf qu'elle développe une liste de chaînes de caractères utilisée pour créer le tableau de lignes retourné, ce qui nécessite plus de mémoire. Cependant, elle renvoie String[] et non un IEnumerable<String> vous permettant d'accéder aux lignes de manière aléatoire.

var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
  var line = lines[i];
  // Process line
}

Utilisation de String.Split

Cette méthode est considérablement plus lente, du moins pour les gros fichiers (testée sur un fichier de 511 Ko), probablement en raison de la façon dont les fichiers sont traités. String.Split est mis en œuvre. Il alloue également un tableau pour toutes les lignes, ce qui augmente la mémoire requise par rapport à votre solution.

using (var streamReader = File.OpenText(fileName)) {
  var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  foreach (var line in lines)
    // Process line
}

Ma suggestion est d'utiliser File.ReadLines parce qu'il est propre et efficace. Si vous avez besoin d'options de partage spéciales (par exemple vous utilisez FileShare.ReadWrite ), vous pouvez utiliser votre propre code mais vous devez augmenter la taille du tampon.

1 votes

Merci pour cet article. L'inclusion du paramètre de taille de la mémoire tampon dans le constructeur de StreamReader a été très utile. Je diffuse des flux à partir de l'API S3 d'Amazon, et l'utilisation d'une taille de tampon correspondante accélère considérablement les choses en conjonction avec ReadLine().

0 votes

Je ne comprends pas. En théorie, la grande majorité du temps passé à lire le fichier serait le temps de recherche sur le disque et les frais généraux de gestion des flux, comme ce que vous feriez avec File.ReadLines. File.ReadLines, quant à lui, est censé lire tout le contenu d'un fichier dans la mémoire en une seule fois. Comment pourrait-il être moins performant ?

2 votes

Je ne peux pas me prononcer sur les performances en termes de vitesse, mais une chose est sûre : il est bien pire en termes de consommation de mémoire. Si vous devez gérer de très gros fichiers (GB par exemple), c'est très critique. Encore plus si cela signifie qu'il doit échanger de la mémoire. Du côté de la vitesse, vous pourriez ajouter que ReadAllLine doit lire TOUTES les lignes AVANT de retourner le résultat, ce qui retarde le traitement. Dans certains scénarios, l'IMPRESSION de la vitesse est plus importante que la vitesse brute.

214voto

Jon Skeet Points 692016

Si vous utilisez .NET 4, utilisez simplement File.ReadLines qui fait tout pour vous. Je pense que c'est beaucoup le même que le vôtre, sauf qu'il peut aussi utiliser FileOptions.SequentialScan et un tampon plus grand (128 semble très petit).

0 votes

Un autre avantage de ReadLines() est paresseux et fonctionne donc bien avec LINQ.

45voto

Free Coder 24 Points 199

Alors que File.ReadAllLines() est l'une des façons les plus simples de lire un fichier, c'est aussi l'une des plus lentes.

Si vous voulez juste lire des lignes dans un fichier sans faire grand-chose, selon ces critères de référence Pour lire un fichier, le moyen le plus rapide est la vieille méthode :

using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
               //do minimal amount of work here
        }
}

Cependant, si vous devez faire beaucoup de choses avec chaque ligne, alors cet article conclut que la meilleure méthode est la suivante (et il est plus rapide de pré-allouer une chaîne[] si vous savez combien de lignes vous allez lire) :

AllLines = new string[MAX]; //only allocate memory here

using (StreamReader sr = File.OpenText(fileName))
{
        int x = 0;
        while (!sr.EndOfStream)
        {
               AllLines[x] = sr.ReadLine();
               x += 1;
        }
} //Finished. Close the file

//Now parallel process each line in the file
Parallel.For(0, AllLines.Length, x =>
{
    DoYourStuff(AllLines[x]); //do your work here
});

2voto

Kibbee Points 36474

Si vous disposez de suffisamment de mémoire, j'ai constaté des gains de performance en lisant le fichier entier dans un fichier de type flux de mémoire et ensuite ouvrir un lecteur de flux sur celui-ci pour lire les lignes. Tant que vous prévoyez de lire l'ensemble du fichier, cela peut apporter quelques améliorations.

1 votes

File.ReadAllLines semble être un meilleur choix alors.

1voto

zmilojko Points 1245

Si vous visez la vitesse d'exécution, oui, vous le faites. Le code pourrait être plus court en utilisant le constructeur de StreamReader.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X