Chunkedxml, lire du xml par morceau

Soyez le premier à donner votre avis sur cette source.

Snippet vu 5 777 fois - Téléchargée 16 fois

Contenu du snippet

Cette classe à pour vocation de fournir une fonctionnalité légère pour la lecture de gros flux XML
Certains flux xml (notamment ceux utilisés par mes script de collecte de données) peuvent être très volumineux (20 à 100 Mo, quand c'est pas du Go).
Leur lecture par des procédés classiques :
- SAX and Co
- analyse par expression rationnelle de la globalité du flux présent en mémoire
fait souvent déborder la mémoire (Heap Space).

L'idée est donc de fournir un service de lecture de ces flux par morceau (chunk), afin de limiter la consommation de mémoire et surtout de permettre la lecture complète du flux sans faire tomber le script en dépassement de capacité mémoire (Heap Overflow)

Source / Exemple :


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**

  • Cette classe à pour vocation de fournir une fonctionnalité légère pour la lecture de gros flux XML.
  • Certains flux xml (notamment ceux utilisés par mes script de collecte de données)
  • peuvent être très volumineux (20 à 100 Mo, quand c'est pas du Go).
  • <br/>
  • Leur lecture par des procédés classiques :
  • <ul>
  • <li>SAX and Co</li>
  • <li>analyse par expression rationnelle de la globalité du flux présent en mémoire</li>
  • </ul>
  • fait souvent déborder la mémoire (Heap Space).
  • <br/>
  • L'idée est donc de fournir un service de lecture de ces flux par morceau (chunk),
  • afin de limiter la consommation de mémoire et surtout de permettre la lecture complète du flux
  • sans faire tomber le script en dépassement de capacité mémoire (Heap Overflow)
  • <br/>
  • 1) Principe de fonctionnement de cette classe :
  • <br/><br/>
  • On instancie un objet de la classe en fournissant :
  • <br/>
  • <ul>
  • <li>le nom du fichier XML à morceler</li>
  • <li>le texte de la balise qui va délimiter les morceaux</li>
  • </ul>
  • L'instanciation, vérifie l'existence du flux et prépare sa lecture.
  • <br/><br/>
  • 2) On appelle la méthode getNextChunk() chaque fois qu'on veut un morceau du flux.
  • La méthode répondra par une chaîne correspondant au morceau suivant ou null lorsqu'elle est arrivée en fin de flux.
  • <br/><br/>
  • Dans un premier temps, il s'agit de permettre la lecture de fichiers locaux téléchargés manuellement.
  • Mais l'idéal serait de permettre le téléchargement du flux depuis son url d'origine, sa décompression et sa lecture.
  • <br/><br/>
  • @author AlexN
*
  • /
public class ChunkedXML { // Propriétés de construction private String filename; // nom du fichier (ou url (TODO)) private String delimiter; // texte non xml de la balise délimitant les morceaux // Propriétés internes private Boolean isValid; // indicateur si le nom de fichier ou l'url fournie correspond à une ressource disponible private File file; // objet fichier pour la lecture par morceaux private FileInputStream stream; // flux de lecture /**
  • Point d'entrée du programme de test
  • @param args
  • /
public static void main(String[] args) { ChunkedXML myXML = new ChunkedXML("my.xml", "chunck"); String chunk; while ((chunk = myXML.getNextChunk()) != null) { System.out.println(chunk.length() + " " + chunk); chunk = null; // Déréférencement des données pour aider le Garbage Collector } } /**
  • Constructeur de ChunkedXML
  • @param filename : nom du fichier
  • @param delimiter : texte brut de la balise de délimitation "balise" et non "</balise>".
  • Le delimiteur n'a pas besoin d'être capitalisé (compareIgnoreCase() pour la recherche du délimiteur)
  • /
public ChunkedXML(String filename, String delimiter) { this.filename = filename; this.delimiter = delimiter; this.isValid = isValid(); // vérification de la validité du flux et préparation de sa lecture } /**
  • Verifie que les paramètres du constructeur sont valides
  • @return : vrai ou faux selon le résultat des tests
  • /
private Boolean isValid() { if (this.filename == null) { System.err.println("La référence au fichier est nulle : WTF ???"); return false; } this.file = new File(this.filename); // Le fichier existe-t-il et est-il lisible ? if(!this.file.canRead()) { System.err.println("Je ne peux pas lire le fichier (introuvable ou illisible) : " + this.filename); return false; } // Le fichier contient-il quelquechose ? if(this.file.length() == 0L) { System.err.println("Le fichier est vide : " + this.filename); return false; } // Préparation du flux de lecture try { this.stream = new FileInputStream(this.file); } catch(FileNotFoundException e){ System.err.println("Je ne peux pas convertir le fichier en flux de lecture : " + this.filename); return false; } // Tout semble ok return true; } /**
  • Méthode pour savoir s'il reste des caractères disponibles dans le flux xml
  • @return vrai ou faux selon qu'il reste des caractères dans le flux xml
  • /
public boolean isAvailable() { try { return (this.stream.available() > 0); } catch(IOException e) { return false; } } /**
  • Lit un morceau du flux xml et s'arrête au délimiteur
  • @return le morceau de flux xml qui a été lu.
  • /
public String getNextChunk() { try { if (!this.isValid || this.stream.available() <= 0) return null; StringBuffer tag = new StringBuffer(); ByteArrayOutputStream baos = new ByteArrayOutputStream((int)this.file.length()); boolean inTag = false; while (true) { int byteRead = this.stream.read(); if (byteRead < 0) break; if (byteRead == '<') { inTag = true; tag = new StringBuffer(); tag.append((char)byteRead); } else if (inTag) { if (byteRead != ' ') tag.append((char)byteRead); // Ignorer les espaces if (byteRead == '>') { inTag = false; StringBuffer xmlTag = new StringBuffer("</"); xmlTag.append(this.delimiter); xmlTag.append(">"); if (tag.toString().equalsIgnoreCase(xmlTag.toString())) { baos.write(byteRead); break; } } } baos.write(byteRead); } baos.flush(); String chunk = new String(baos.toByteArray()); baos.close(); baos = null; // Déréférencement des données pour aider le Garbage Collector return chunk; } catch(IOException e) { System.err.println("Problème IO lors de la lecture du flux"); } return null; } }

Conclusion :


Fichier d'exemple (my.xml) :

<root>

<chunck>
<data1>this is the data 1 for chunk 1</data1>
<data2>this is the data 2 for chunk 1</data2>
<data3>this is the data 3 for chunk 1</data3>
</chunck>
<chunck>
<data1>this is the data 1 for chunk 2</data1>
<data2>this is the data 2 for chunk 2</data2>
<data3>this is the data 3 for chunk 2</data3>
</chunck>
<chunck>
<data1>this is the data 1 for chunk 3</data1>
<data2>this is the data 2 for chunk 3</data2>
<data3>this is the data 3 for chunk 3</data3>
</chunck>
<chunck>
<data1>this is the data 1 for chunk 4</data1>
<data2>this is the data 2 for chunk 4</data2>
<data3>this is the data 3 for chunk 4</data3>
</chunck>

</root>

A voir également

Ajouter un commentaire

Commentaires

Messages postés
5351
Date d'inscription
dimanche 4 mai 2003
Statut
Modérateur
Dernière intervention
17 août 2020
97
Salut,

le code est de bonne qualité (+1 pour le commentaire de boumarsel), mais comme je maudit le XML je ne testerai pas...
Messages postés
694
Date d'inscription
lundi 5 décembre 2005
Statut
Membre
Dernière intervention
8 janvier 2014
13
Merci ;o)
Messages postés
298
Date d'inscription
jeudi 12 juin 2003
Statut
Membre
Dernière intervention
9 juillet 2008
1
Bonjour,

Je ne sais pas si ça a été dit ou non mais une chose que j'apprécie c'est le respect du standard pour la doc/commentaires dans le code.

Cordialement
Messages postés
2448
Date d'inscription
samedi 21 février 2004
Statut
Modérateur
Dernière intervention
29 janvier 2010
12
ouais je suis d'accord mais la c'est 4o
ya des classes ca pourrais etre BEAUCOUP plus

et 4o par ci, 4o par la ... ca monte vite
les optimisations que l'ont peu faire des le debut autant les faire ...
je ne sais pas comment se debrouille le GC dans ce cas mais il y a des chance que se soit plus rapide...
Messages postés
30
Date d'inscription
mercredi 20 février 2008
Statut
Membre
Dernière intervention
24 avril 2009

C'est sûr que là on est en plein chipotage quand on voit la puissance des machines actuelles ça m'étonnerais qu'il y ait une différence mesurable entre les deux solutions...
Afficher les 15 commentaires

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.