web-dev-qa-db-fra.com

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 fais le plus efficacement possible dans le cadre de .NET C #.

C'est ce que j'essaie 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
}
294
Loren C Fortner

Pour trouver le moyen le plus rapide de lire un fichier ligne par ligne, vous devez procéder à des analyses comparatives. 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

Ceci est fondamentalement votre méthode. Pour une raison quelconque, vous définissez la taille de la mémoire tampon sur la valeur la plus petite possible (128). Augmenter cela augmentera en général les performances. La taille par défaut est 1 024 et les autres bons choix sont 512 (taille du secteur sous Windows) ou 4 096 (taille du cluster sous NTFS). Vous devrez exécuter un test de performance pour déterminer une taille optimale de la mémoire tampon. Un tampon plus grand est - sinon plus rapide - du moins pas plus 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 constructeur FileStream vous permet de spécifier FileOptions . Par exemple, si vous lisez un fichier volumineux de manière séquentielle du début à la fin, vous pouvez utiliser _FileOptions.SequentialScan_. Encore une fois, l'analyse comparative est la meilleure chose à faire.

Utilisation de File.ReadLines

Cela ressemble beaucoup à votre propre solution, sauf qu’elle est implémentée à l’aide de StreamReader avec une taille de mémoire tampon fixe de 1 024. Sur mon ordinateur, les performances sont légèrement meilleures que celles de votre code avec une taille de mémoire tampon de 128. Toutefois, vous pouvez obtenir la même augmentation de performances en utilisant une taille de mémoire tampon plus grande. Cette méthode est implémentée à l'aide d'un bloc itérateur 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

Cela ressemble beaucoup à la méthode précédente, à la différence que cette méthode augmente la liste des chaînes utilisées pour créer le tableau de lignes renvoyé, de sorte que les besoins en mémoire sont plus importants. Cependant, il retourne _String[]_ et non un _IEnumerable<String>_ vous permettant d'accéder de manière aléatoire aux lignes.

_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 sur les gros fichiers (testée sur un fichier de 511 Ko), probablement en raison de la façon dont _String.Split_ est implémenté. 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 car c'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 de la mémoire tampon.

276
Martin Liversage

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

196
Jon Skeet

Bien que File.ReadAllLines() soit l’un des moyens les plus simples de lire un fichier, c’est aussi l’un des plus lents.

Si vous souhaitez simplement lire les lignes d’un fichier sans trop en faire, d’après ces points de repère , le moyen le plus rapide de lire un fichier est la méthode ancienne de:

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 avec chaque ligne, alors cet article conclut que le meilleur moyen est le suivant (et qu'il est plus rapide de pré-allouer une chaîne [] si vous savez combien de lignes vous avez 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
});
33
Free Coder 24

Utilisez le code suivant:

foreach (string line in File.ReadAllLines(fileName))

Ce fut une énorme différence dans les performances de lecture.

Cela a un coût de consommation de mémoire, mais en vaut la peine!

9
user2671536

Si la taille du fichier n'est pas grande, il est plus rapide de lire tous les fichiers, puis de scinder la chaîne:

var filestreams = sr.ReadToEnd().Split(Environment.NewLine, 
                              StringSplitOptions.RemoveEmptyEntries);
3
Saeed Amiri

Il y a un bon sujet à ce sujet dans la question Stack Overflow Le rendement est-il plus lent que le retour à l'ancienne?.

Ça dit:

ReadAllLines charge toutes les lignes en mémoire et retourne une chaîne []. Tout va bien si le fichier est petit. Si le fichier est plus volumineux que ce qui est contenu dans la mémoire, vous manquerez de mémoire.

ReadLines, d’autre part, utilise rendement retour pour retourner une ligne à la fois. Avec lui, vous pouvez lire un fichier de toute taille. Il ne charge pas tout le fichier en mémoire.

Supposons que vous vouliez trouver la première ligne contenant le mot "foo", puis quittez. À l’aide de ReadAllLines, vous devez lire l’ensemble du fichier en mémoire, même si "foo" apparaît sur la première ligne. Avec ReadLines, vous ne lisez qu'une seule ligne. Lequel serait le plus rapide?

3
Marcel James

Si vous avez assez de mémoire, j'ai constaté des gains de performances en lisant l'intégralité du fichier dans un flux de mémoire , puis en ouvrant un lecteur de flux pour lire les lignes. Tant que vous envisagez de toute façon de lire le fichier dans son intégralité, cela peut apporter certaines améliorations.

1
Kibbee

Vous ne pouvez pas aller plus vite si vous voulez utiliser une API existante pour lire les lignes. Mais la lecture de gros morceaux et la recherche manuelle de chaque nouvelle ligne dans le tampon de lecture seraient probablement plus rapides.

1
jgauffin