Conversion d'InputStream texte en String : refactoring
Par Shlublu le mardi 12 juillet 2011, 20:56 - Tutoriel Java - Lien permanent
Il arrive assez fréquemment que l'on ait besoin de convertir en String le contenu d'un InputStream texte retourné par telle ou telle méthode. Il peut s'agir de contenus de fichiers textes, de pages lues sur internet, etc[1].
On se dit que c'est une boucle simple, que cela prend deux lignes... puis l'on s'aperçoit qu'il y a des Exceptions à intercepter, et l'on se surprend parfois même à utiliser le coûteux opérateur + de la classe String plutôt que d'utiliser un StringBuilder (ou un StringBuffer si l'on est en API 1.x).
Enfin, vu que l'on a plusieurs flux à convertir de cette façon et en des endroits très différents du code, on finit avec le même bloc de 8 à 10 lignes copié-collé un peu partout.
Et c'est mal.
Pour traiter ce genre de cas proprement, il est pratique d'avoir dans sa librairie personnelle une classe utilitaire de ce type :
import java.io.IOException; import java.io.InputStream; public class TextHelper { /** * Convertit un InputStream en String. * @param in InputStream, non nul, à lire * @param bufSize Taille du buffer de lecture, en octets * @return String Chaîne contenant l'intégralité de l'InputStream in */ public static String InputStreamToString (InputStream in, int bufSize) { // En API 1.x, il faut utiliser un StringBuffer // à la place du StringBuilder ci-dessous : final StringBuilder out = new StringBuilder(); // Buffer de lecture final byte[] buffer = new byte[bufSize]; try { // On ajoute le contenu du flux au StringBuilder for (int ctr; (ctr = in.read(buffer)) != -1;) { out.append(new String(buffer, 0, ctr)); } } catch (IOException e) { throw new RuntimeException("Cannot convert stream to string", e); } // On retourne la chaîne contenant les données de l'InputStream return out.toString(); } /** * Convertit un InputStream en String. * @param in InputStream, non nul, à lire * @return String Chaîne contenant l'intégralité de l'InputStream in */ public static String InputStreamToString (InputStream in) { // On appelle la méthode précedente avec une taille de buffer par défaut return InputStreamToString(in, 1024); } }
Et voilà.
Il suffit dorénavant d'appeler TextHelper.InputStreamToString(InputStream) pour obtenir une chaîne contenant l'intégralité des données du flux.
Si l'on en connaît la taille approximative, ou si l'on souhaite optimiser l'usage fait de la mémoire, on préférera appeler appeler TextHelper.InputStreamToString(InputStream, int) afin de spécifier la taille du buffer à utiliser.
Si une exception se produit lors du traitement, trois écoles :
- Soit on l'intègre à une
RuntimeExceptioncar aucun traitement applicatif ne donnerait satisfaction: c'est le choix effectué ici.
- Soit on l'intègre à son propre type d'exception que l'on déclare par un
throwsen lieu et place de laRuntimeExceptionremontée dans cet exemple.
- Soit enfin on la remonte directement, auquel cas on supprime le bloc
try/catchpour ne garder que la bouclefor ( ; ; )de lecture du flux et l'on déclare unthrows IOException.
La particularité de la RuntimeException est de ne pas nécessiter de déclaration throws spécifique, l'exception n'ayant pas vocation à être interceptée (plus de détails ici). Ce type d'exceptions, dont NullPointerException, ClassCastException ou
encore IndexOutOfBoundException font partie, est idéal pour tous les cas d'erreurs ne pouvant être traités par l'application elle-même car relevant d'une erreur de programmation ou encore de matériel.
Les deux derniers choix sont quant à eux appropriés dans le cas de flux liés au réseau par exemple, afin de permettre la gestion d'une coupure réseau par l'application.
En fonction des cas d'utilisation, on pourra donc être amené à préférer l'une ou l'autre de ces options, ce qui peut conduire à l'implémentation de plusieurs méthodes.
Enfin, cette classe peut-être enrichie de toutes les méthodes de traitement de données texte dont on a fréquemment besoin.
Notes
[1] En faisant tout de même attention à la mémoire.