web-dev-qa-db-fra.com

Quelle est la meilleure façon de lire un fichier dans la liste <string>

J'utilise une liste pour limiter la taille du fichier car la cible est limitée en disque et en ram . C'est ce que je fais maintenant mais existe-t-il un moyen plus efficace?

readonly List<string> LogList = new List<string>();
...
var logFile = File.ReadAllLines(LOG_PATH);
foreach (var s in logFile) LogList.Add(s);
46
jacknad
var logFile = File.ReadAllLines(LOG_PATH);
var logList = new List<string>(logFile);

logFile étant un tableau, vous pouvez le transmettre au constructeur List<T>. Ceci élimine les coûts inutiles lors d'une itération sur le tableau ou de l'utilisation d'autres classes IO.

Implémentation réelle du constructeur :

public List(IEnumerable<T> collection)
{
        ...
        ICollection<T> c = collection as ICollection<T>;
        if( c != null) {
            int count = c.Count;
            if (count == 0)
            {
                _items = _emptyArray;
            }
            else {
                _items = new T[count];
                c.CopyTo(_items, 0);
                _size = count;
            }
        }   
        ...
} 
92
Evan Mulawski

Pourquoi ne pas utiliser un générateur à la place?

private IEnumerable<string> ReadLogLines(string logPath) {
    using(StreamReader reader = File.OpenText(logPath)) {
        string line = "";
        while((line = reader.ReadLine()) != null) {
            yield return line;
        }
    }
}

Ensuite, vous pouvez l'utiliser comme vous utiliseriez la liste:

var logFile = ReadLogLines(LOG_PATH);
foreach(var s in logFile) {
    // Do whatever you need
}

Bien sûr, si vous devez avoir un List<string>, vous devrez alors conserver le contenu complet du fichier en mémoire. Il n'y a vraiment aucun moyen de contourner cela.

12
Daniel Pryden

[Modifier]

Si vous effectuez cette opération pour supprimer le début d'un fichier journal, vous pouvez éviter de charger tout le fichier en procédant comme suit:

// count the number of lines in the file
int count = 0;
using (var sr = new StreamReader("file.txt"))
{
    while (sr.ReadLine() != null) 
        count++;
}

// skip first (LOG_MAX - count) lines
count = LOG_MAX - count;
using (var sr = new StreamReader("file.txt"))
using (var sw = new StreamWriter("output.txt"))
{
    // skip several lines
    while (count > 0 && sr.ReadLine() != null) 
        count--;

    // continue copying
    string line = "";
    while (line = sr.ReadLine() != null)
        sw.WriteLine(line);
}

Tout d’abord, puisque File.ReadAllLines charge la totalité du fichier dans un tableau de chaînes (string[]), la copie dans une liste est redondante.

Deuxièmement, vous devez comprendre qu'une List est implémentée en utilisant un tableau dynamique sous le capot. Cela signifie que le CLR devra allouer et copier plusieurs baies jusqu'à ce qu'il puisse gérer l'intégralité du fichier. Étant donné que le fichier est déjà sur le disque, vous pouvez envisager de traiter rapidement la vitesse de la mémoire, de travailler directement sur les données du disque ou de la traiter par petits morceaux.

  1. Si vous devez le charger entièrement en mémoire, essayez au moins de le laisser dans un tableau:

     string[] lines = File.ReadAllLines("file.txt");
    
  2. S'il doit vraiment s'agir d'une List, chargez les lignes une par une:

     List<string> lines = new List<string>();
     using (var sr = new StreamReader("file.txt"))
     {
          while (sr.Peek() >= 0)
              lines.Add(sr.ReadLine());
     }
    

    Remarque: List<T> a un constructeur qui accepte un paramètre de capacité. Si vous connaissez le nombre de lignes à l'avance, vous pouvez empêcher plusieurs allocations en préallouant à l'avance le tableau:

     List<string> lines = new List<string>(NUMBER_OF_LINES);
    
  3. Mieux encore, évitez de stocker tout le fichier en mémoire et traitez-le "à la volée":

     using (var sr = new StreamReader("file.txt"))
     {
          string line;
          while (line = sr.ReadLine() != null) 
          {
              // process the file line by line
          }
     }
    
5
Groo

Ne le stockez pas si possible. Lisez-le simplement si votre mémoire est contrainte. Vous pouvez utiliser un StreamReader:

using (var reader = new StreamReader("file.txt"))
{
    var line = reader.ReadLine();
    // process line here
}

Cela peut être encapsulé dans une méthode qui génère des chaînes par ligne lue si vous souhaitez utiliser LINQ.

4
Deleted
//this is only good in .NET 4
//read your file:
List<string> ReadFile = File.ReadAllLines(@"C:\TEMP\FILE.TXT").ToList();

//manipulate data here
foreach(string line in ReadFile)
{
    //do something here
}

//write back to your file:
File.WriteAllLines(@"C:\TEMP\FILE2.TXT", ReadFile);
2
User2325641
List<string> lines = new List<string>();
 using (var sr = new StreamReader("file.txt"))
 {
      while (sr.Peek() >= 0)
          lines.Add(sr.ReadLine());
 }

je suggérerais ceci ... de la réponse de Groo.

1
user240141

string inLine = reader.ReadToEnd (); myList = inLine.Split (nouvelle chaîne [] {"\ r\n"}, StringSplitOptions.None) .ToList ();

Cette réponse passe à côté du point initial, à savoir qu'ils obtenaient une erreur OutOfMemory. Si vous continuez avec la version ci-dessus, vous êtes sûr de le valider si votre système ne dispose pas du RAM CONTIGUOUS approprié pour charger le fichier.

Vous devez simplement le diviser en parties, et soit stocker en tant que liste ou chaîne [] de toute façon. 

0
RTZ ZZ

Vous pouvez simplement lire de cette façon. 

List<string> lines = System.IO.File.ReadLines(completePath).ToList();
0
Ammar The Trainer
string inLine = reader.ReadToEnd();
myList = inLine.Split(new string[] { "\r\n" }, StringSplitOptions.None).ToList();

J'utilise aussi Environment.NewLine.toCharArray également, mais j'ai constaté que cela ne fonctionnait pas avec quelques fichiers se terminant par\r\n. Essayez l'une ou l'autre et j'espère que cela fonctionnera bien pour vous.

0
vSteve