IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Accès rapide au fichier, puis récupération du contenu sous form de mot clé


Sujet :

Java

  1. #1
    Membre à l'essai
    Inscrit en
    Décembre 2008
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 21
    Points : 19
    Points
    19
    Par défaut Accès rapide au fichier, puis récupération du contenu sous form de mot clé
    Bonjour tt le monde;

    pour un besoin d'indexation, je dois dans mon appli récupérer le contenu des fichiers ajoutés (formats supportés : Txt, Doc, rtf, Xls, PDF, JPG, GIF) et stocké par la suite tous les mots dans la base (mots-clés). pour faire, j'ai commencé par les fichiers text, mais le problème c'est que mon code est très lourds en éxécution (pour un fichier txt de 36.7 Mo il a pris 10 min)

    Veuillez SVP me suggérer d'autres solutions afin de rendre mon code plus rapide et performant (Utilisation du Hashcode, lecture du fichier ligne par ligne...).

    Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    public static void main(String[] args)
    	{
    		System.out.println("Date de début : " + new Date());
     
    		File fich = new File("C:\\FTP\\test_java.txt");
    		int n;
    		char c;
    		String mot = "";
    		Collection<String> col = new ArrayList<String>();
     
    		try {
    			FileReader fr = new FileReader(fich);
     
    			while ((n = fr.read()) != -1)
    			{
    				c =(char) n;
    				if (c != ' ' && c != '\r' && c != '\n' && c != '.' && c != ',' && c != ';' && c != ':'
    					&& c != '!' && c != '?' && c != '/' && c != '\\' && c != '$' && c != '"'
    					&& c != '&' && c != '(' && c != ')' && c != '[' && c != ']'
    					&& c != '{' && c != '}' && c != '@' && c != '*' && c != '%')
    					mot = mot + c;
    				else
    				{
    					if (mot.length() > 3 && !col.contains(mot.toLowerCase()))
    					{
    						col.add(mot.toLowerCase());
    					}
    				mot = "";
    				}
    			}
    			fr.close();
    			col.clear();
    			col = null;
    			System.out.println("Date de fin : " + new Date());
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    Merci infiniment pour votre collaboration habituelle.

  2. #2
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Ouch!

    la lecture byte par byte c'est vraiment pas le top. Mieux vaut lire par paquet de dison 10Ko (via un byte[]).

    La lecture ligne par ligne avec un bufferedreader est également une option, et peut-être même mieux (tu récupère directement des string et pas des byte[])


  3. #3
    Membre à l'essai
    Inscrit en
    Décembre 2008
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 21
    Points : 19
    Points
    19
    Par défaut
    Merci Pill_S pour votre réponse.

    je me suis dit, si je récupère ligne par ligne, je dois ensuite retravailler la chaine pour récupérer les mots en éliminant les doublons, les espaces, les caractères de numértotation... je pense que ca sera plus lourd.
    Bon, pour faire court et simple, mon besoin et de pouvoir récupérer du fichier tous les mots ayant une taille > à 3 et les stocké dans ma table indéxé, afin de pouvoir faire par la suite une recherche en Fulltext sur le document ajouté.

    Merci.

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Même si tu n'a pas l'utilité d'une lecture ligne par ligne, tu peux utiliser un BufferedReader pour regrouper les lectures :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // FileReader fr = new FileReader(fich);
    Reader fr = new BufferedReader(FileReader(fich));
    Pour un fichier de 30Mo tu passes de 30 000 000 accès IO à moins de 4000 (lecture par buffer de 8192 par défaut).



    Ensuite il faut éviter les multiples concaténations de String. Ce n'est pas fait pour cela et il est préférable d'utiliser des StringBuilder à la place :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //String mot = "";
    StringBuilder builder = new StringBuilder();
     
     
    ...
     
     
    	if (c != ' ' && c != '\r' && c != '\n' && c != '.' && c != ','
    			&& c != ';' && c != ':' && c != '!' && c != '?'
    			&& c != '/' && c != '\\' && c != '$' && c != '"'
    			&& c != '&' && c != '(' && c != ')' && c != '['
    			&& c != ']' && c != '{' && c != '}' && c != '@'
    			&& c != '*' && c != '%')
    		// mot = mot + c;
    		builder.append(c);
    	else {
    		String mot = builder.toString().toLowerCase();
    		if (mot.length() > 3 && !col.contains(mot)) {
    			col.add(mot);
    		}
    		// mot = "";
    		builder.setLength(0);
    	}
    Dans une boucle, la concaténation de String génère de multiples objets temporaires qui surcharge le GC. Il faut réserver cela à un usage ponctuelle. Pour la génération de chaine on doit utiliser les StringBuffer/StringBuilder...


    Avec ces deux corrections tu devrais déjà bien boosté ton code...

    Reste ensuite à utiliser un try/finally pour fermer le flux


    a++

  5. #5
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 804
    Points
    48 804
    Par défaut
    pour indexer des document, pour information, il existe des librairies comme lucene. Avantages: support de plusieurs format texte déjà existant, recherche partielle, reconnaissance des mots similaire (pluriels, féminins, etc) avec indexation uniquement sous la forme basique du nom.

  6. #6
    Membre à l'essai
    Inscrit en
    Décembre 2008
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 21
    Points : 19
    Points
    19
    Par défaut
    Tout d'abord je vous remercie infiniment (Pill_S, adiGuba et tchize_) pour toutes les suggéstions que vous m'avez proposé. vous prouvez chaque jour un haut niveau de compétence.

    J'ai optimisé mon code en suivant vos conseils, et apparement ça à l'air mieux.
    Mais j'ai trouvé en fin de compte que l'instruction d'ajout du mot à la collection --> ( col.add(mot); ) est celle qui alourdit le traitement, en désactivant cette dernière, je passe de 10 min à 4 sec !!! mais je n'ai pas d'autre moyen, car normalement cette collection est mappé avec avec une table (j'utilise Hibernate). j'espère que j'été clair.

    Par rapport à Lucen, je pense que c'est une bonne idée, je vais me documenter un peu, et je vais vous faire part.
    L'objectif c'est de trouver une sollution finale et mettre en résolu la discussion

    Merci encore une fois pour votre collaboration et entraide.
    A+

  7. #7
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Si c'est si lent, c'est sûrement à cause de fréquent redimensionnements du tableau interne de l'ArrayList que tu utilises.

    Tu peux;

    1) soit utiliser une LinkedList (qui n'a pas de tableau interne)
    2) soit initialiser la taille du tableau lors de la création (new ArrayList<String>(2*1000*1000))


  8. #8
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Ou utiliser un HashSet qui gère l'unicité des éléments via une hash table...

    a++

  9. #9
    Membre à l'essai
    Inscrit en
    Décembre 2008
    Messages
    21
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 21
    Points : 19
    Points
    19
    Par défaut
    Enfin, j'ai arrivé à optimiser mon code, et bien sûre c'est graçe à vous. merci encore une fois.
    J'ai utilisé le HashSet, c'est formidable comme Collection, l'accès à cette dernière est aléatoire et elle gère l'unicité d'une manière robuste.
    Voici la dernière version du code, je suis hyper content parce que j'ai passé de 10 min à quelques secondes !!!
    Je tiens à partagé ce que j'ai fait avec vous, et j'espère qu'il sera utile pour d'autres.
    Voici le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    public static void main(String[] args) throws IOException
    	{
    		System.out.println("Date de début : " + new Date());
     
    		File fich = new File("C:\\FTP\\test_java.txt");
    		int n;
    		char c;
    		Collection<String> col = new HashSet<String>();
    		StringBuilder builder = new StringBuilder();
    		Reader fr = null;
     
    		try {
    			fr = new BufferedReader(new FileReader(fich), 8192 * 1024);
     
    			while ((n = fr.read()) != -1)
    			{
    				c =(char) n;
    				if (c != ' ' && c != '\r' && c != '\n' && c != '.' && c != ',' && c != ';' && c != ':'
    					&& c != '!' && c != '?' && c != '/' && c != '\\' && c != '$' && c != '"'
    					&& c != '&' && c != '(' && c != ')' && c != '[' && c != ']'
    					&& c != '{' && c != '}' && c != '@' && c != '*' && c != '%' && c != '-'
    					&& c != '*' && c != '+' && c != '=')
    					builder.append(c);
    				else
    				{
    					if (builder.length() > 3 && !col.contains(builder.toString().toLowerCase()))
    						col.add(builder.toString().toLowerCase());
     
    				builder.setLength(0);
    				}
    			}
    			System.out.println("Date de fin    : " + new Date());
    		} catch (FileNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		finally {
    			System.out.println(col);
    			fr.close();
    			col.clear();
    			col = null;
    		}
    	}
    Bon, si vous voyez qu'il reste d'autres modifications à apporter, n'hésitez pas SVP. Pour rappel l'objectif est d'extraire d'un fichier tous les mots ayant une taille > à 3 tout en éliminant les doublons ainsi que les caractère de numérotation. ça sera très gentil de votre part si vous répondiez à ce dernier post, afin de clôturer la discussion.

    Je tiens à vous remercier tous, adiGuba, Pill_S et tchize_ pour toutes les suggestions que vous m'avez proposé à grand coeur.
    A+ mes amis

Discussions similaires

  1. [CR XI] Est-il possible à partir du nom d'un fichier d'afficher son contenu sous CR XI ?
    Par juju05 dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 17/04/2015, 16h13
  2. Generer un fichier et lire son contenu sous Zend
    Par cyprien95 dans le forum Zend Framework
    Réponses: 2
    Dernier message: 15/10/2012, 09h11
  3. Generer un fichier et lire son contenu sous Zend
    Par cyprien95 dans le forum Framework .NET
    Réponses: 1
    Dernier message: 07/10/2012, 23h03
  4. accès rapide à un fichier texte volumineux
    Par Shrine dans le forum C++
    Réponses: 2
    Dernier message: 12/03/2007, 16h25
  5. Réponses: 2
    Dernier message: 16/06/2005, 14h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo