C#: gestoion de la mémoire [Résolu]

Karibot 89 Messages postés mardi 19 janvier 2010Date d'inscription 21 juin 2016 Dernière intervention - 22 oct. 2010 à 16:51 - Dernière réponse : cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention
- 22 oct. 2010 à 23:35
bonjour à tous,
j'ai un gros fichier que j'essaye de dédupliquer...
pour cela je fais un Dictionnary<>, et je compte en meme temps le nombre d'occurence de chaque ligne, sauf que la mémoire n'en peut plus. le fichier fait plusieurs millions de lignes (2,4Go)
j'essaye de trouver un moyen de pouvoir aller au bout de ma tache sans faire plater le programme à chaque fois (ce que je comprend puisqu'il charge tout dans le dico qui bouffe ma RAM).
voici ma fonction:
        public static void Deduplique(string p)
        {
            StreamReader oReader = new StreamReader(p);

            StreamWriter oWriter = new StreamWriter(p+".uniq.txt");

            Dictionary<string, int> dico = new Dictionary<string, int>();
            string line;
            while ((line= oReader.ReadLine()) !=null)
            {
                if (dico.ContainsKey(line))
                    dico[line]++;
                else
                    dico.Add(line, 1);
            }

            foreach (KeyValuePair<string, int> oKv in dico)
            {
                oWriter.WriteLine("{0}\t{1}", oKv.Key, oKv.Value);
            }

            oReader.Close();
            oWriter.Close();
        }


Merci pour votre aide :)
Afficher la suite 

Votre réponse

3 réponses

Meilleure réponse
cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention - 22 oct. 2010 à 19:21
3
Merci
Bonsoir,

Pas simple comme probleme. je suppose que tu n'as pas une base de données sous la main.

perso je pencherais pour un traitement en 2 passes, et j'utiliserais un HashCode pour verifier l'existance de lignes
mais tout dépend des lignes, principalement leur longueur, car le hashcode n'est pas certain, mais ça prend moins de place en mémoire.

ex:
public static void Deduplique(string p)
{
Dictionary lineCounter = new Dictionary();

//premiere passe on compte
using (StreamReader oReader = new StreamReader(p))
{

string line;
while ((line = oReader.ReadLine()) != null)
{
int hash = line.GetHashCode();
if (lineCounter.ContainsKey(hash))
lineCounter[hash]++;
else
lineCounter.Add(hash, 1);
}
}
//Deuxieme passe on écrit
using (StreamReader oReader = new StreamReader(p))
{
string line;
using (StreamWriter oWriter = new StreamWriter(p + ".uniq.txt"))
{
while ((line = oReader.ReadLine()) != null)
{
int hash = line.GetHashCode();
if (lineCounter[hash] >0)//si ==0 alors déjà traitée
{
oWriter.Write(string.Format("{0}\t{1}",line,lineCounter[hash]));
lineCounter[hash]=0;// pour eviter la suppression qui entrainerait une reord du dictionnaire
}
}
}
}
}

bon code
Bob


C# is amazing, enjoy it!

Merci cs_Robert33 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 120 internautes ce mois-ci

Commenter la réponse de cs_Robert33
Karibot 89 Messages postés mardi 19 janvier 2010Date d'inscription 21 juin 2016 Dernière intervention - 22 oct. 2010 à 21:05
0
Merci
Top, merci Robert33.
autre question: quand j'essaye de remplir une list<string> à partir d'un gros fichier, ou remplir un stringBuilder trop gros j'ai aussi ce type d'erreur (outofmemory), comment on peut régler le problème? on n'utilise pas de Using(){} dans ces cas là, non. quelle est l'internative?.
Commenter la réponse de Karibot
cs_Robert33 835 Messages postés samedi 15 novembre 2008Date d'inscription 14 janvier 2017 Dernière intervention - 22 oct. 2010 à 23:35
0
Merci
Salut Karibot,

La clause using permet juste d'être certain que les resources déclarées sont bien liberées, c'est plutot une facilité d'écriture.

une liste, ou un stringbuilder, c'est de la mémoire, quand on a plus assez de mémoire il faut utiliser le disque, c'est pour cela, entre autre, qu'on a créé les base de données.
le travail sur les fichiers ne necessite pas toujours de le monter en memoire, tu peux aussi utiliser des pointeurs de lecture sur le fichier disque.
avec un stream tu peux te déplacer directement dans un fichier et ne stocker en mémoire que les informations minimales

bref, il n'y a pas de solution simple à ce type de probleme, c'est vraiment du cas par cas.

Bob

C# is amazing, enjoy it!
Commenter la réponse de cs_Robert33

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.