2010-12-15 102 views
3

Je travaille en C# et je me suis un gros fichier texte (75MB) Je veux sauver les lignes qui correspondent à une expression régulièreComment obtenir certaines lignes d'un fichier texte dans C#?

J'ai essayé de lire le fichier avec un StreamReader et ReadToEnd, mais il faut 400Mo de RAM

et lors d'une nouvelle utilisation crée une exception de mémoire insuffisante.

J'ai ensuite essayé d'utiliser File.ReadAllLines():

string[] lines = File.ReadAllLines("file"); 

StringBuilder specialLines = new StringBuilder(); 


foreach (string line in lines) 

if (match reg exp) 

    specialLines.append(line); 

cela est grand mais quand ma fonction se termine la mémoire utilisée ne marche pas clair et je suis parti avec 300 Mo de mémoire utilisée, uniquement lors du rappel la fonction et l'exécution de la ligne: string [] lines = File.ReadAllLines ("file"); Je vois la mémoire passer à 50 Mo donner ou prendre, puis ré-attribuer à 200 Mo

Comment puis-je effacer cette mémoire ou obtenir les lignes dont j'ai besoin d'une manière différente?

Répondre

6
 var file = File.OpenRead("myfile.txt"); 
     var reader = new StreamReader(file); 
     while (!reader.EndOfStream) 
     { 
      string line = reader.ReadLine(); 
      //evaluate the line here. 
     } 
     reader.Dispose(); 
     file.Dispose(); 
+1

De même, n'oubliez pas de disposer des objets 'FileStream' et' StreamReader'. –

+0

Merci Matt. Oui, vous avez raison bien sûr. – eoldre

+3

Vous n'avez pas besoin de créer le flux vous-même, le constructeur StreamReader peut prendre directement le nom du fichier. En outre, vous ne devez pas utiliser EndOfStream pour vérifier si vous êtes à la fin du fichier: étant donné que StreamReader met en mémoire tampon les données, la position du flux peut être à la fin avant que StreamReader ne renvoie toutes les lignes –

2

Vous devez diffuser le texte au lieu de charger le fichier entier en mémoire. Voici une façon de le faire, en utilisant une méthode d'extension et LINQ:

static class ExtensionMethods 
{ 
    public static IEnumerable<string> EnumerateLines(this TextReader reader) 
    { 
     string line; 
     while((line = reader.ReadLine()) != null) 
     { 
      yield return line; 
     } 
    } 
} 

... 

var regex = new Regex(..., RegexOptions.Compiled); 
using (var reader = new StreamReader(fileName)) 
{ 
    var specialLines = 
     reader.EnumerateLines() 
       .Where(line => regex.IsMatch(line)) 
       .Aggregate(new StringBuilder(), 
         (sb, line) => sb.AppendLine(line)); 
} 
+1

+1 - J'ajouterais que .NET 4.0 a une méthode similaire déjà implémentée. – ChaosPandion

+0

@ChaosPandion, voulez-vous dire 'File.ReadLines'? Bon à présent, je ne l'ai jamais remarqué auparavant ... –

+0

C'est correct. Rétrospectivement, j'aurais probablement dû le mentionner. :) – ChaosPandion

0

Vous devez utiliser le modèle de recenseur pour garder votre empreinte mémoire faible dans le cas où votre fichier peut être énorme.