ufrima

Approche Orientée Objet
Sébastien LABORIE

Objectif

L'objectif de ce travail consiste à aborder la notion d'entrées/sorties en java. Pour cela, nous allons sauvegarder et restaurer des informations dans des fichiers. Peu importe la nature de cette information, dans notre cas nous utiliserons une classe PointCartesien comme type d'information.
Ce TP sera divisé en 4 parties : Maframe

Une interface vous est proposée pour interagir avec l'utilisateur final. Vous n'aurez qu'à compléter la classe TestIO.java qui vous est fournie en réalisant les corps des méthodes correspondant aux différents exercices. La classe GUI.java définit cette interface utilisateur, la classe TestIO.java est une sous-classe ne comportant que les éléments à compléter.

Fichiers nécessaires

 

1. Manipulations de fichiers textuels

Dans cette partie vous allez implémenter les méthodes charger(File f), sauver(File f) et copier(File f1, File f2) qui respectivement charge le contenu d'un fichier dans la zone de texte, sauve le contenu de la zone de texte dans un fichier et copie le contenu d'un fichier (f1) dans un autre fichier (f2) en affichant ce contenu dans la zone de texte. Pour cela, vous utiliserez les classes FileInputStream, FileReader et FileWriter permettant de lire et écrire dans un fichier. Vous prendrez soin de choisir toujours pertinemment les types que vous utiliserez. Vous disposez dans la classe TestIO de primitives (getZoneDeTexte et setZoneDeTexte) pour obtenir et modifier la valeur de la zone de texte affichée. On supposera que la taille des fichiers n'excède pas la capacité d'un entier (2^31-1). De plus, la méthode warning(String s) vous permettra d'afficher un message à l'utilisateur comme par exemple "fichier correctement sauvegarder"...

1.1 Réalisation de la méthode "charger"

Pour réaliser cette méthode vous utiliserez un FileInputStream en vous servant de la lecture byte par byte (méthode read()) pour l'acquisition ainsi qu'une chaine de caractères comme structure intermédiaire. Vous disposez de la possibilité de connaître le nombre de caractères contenus dans un fichier, ce qui permet de contrôler la boucle d'acquisition. Testez le chargement du fichier test1.txt.

1.2 Réalisation de la méthode "sauver"

Pour réaliser cette méthode vous utiliserez un FileWriter.

1.3 Réalisation de la méthode "copier"

Pour réaliser cette méthode vous utiliserez à la fois un FileReader et un FileWriter en vous servant de la lecture bloquée (méthode read(char[])) pour l'acquisition.

1.4 Optimisation

Testez votre méthode "charger" avec le fichier test100.txt, que constatez-vous ?
Pour améliorer cette situation utilisez comme structure intermédiaire un objet de type StringBuffer permettant la bufferisation d'une chaine de caractères. Refaite le test.
Y-a-t-il une amélioration, si oui à quoi cela est-il dû ? (la solution se trouve dans la compréhension des caractéristiques de la classe String)

1.5 Extension

On souhaite utiliser un WriterArea fourni dans la bibliothèque jus.util, quelles seraient précisément les modifications que vous devriez apporter à la primitive "sauver" pour qu'elle puisse fonctionner indifféremment avec un fichier ou un WriterArea ?

2. Analyse de fichiers textuels et bufferisation

Désormais on souhaite construire dans notre application une collection de PointCartesien à la différence de précédemment où l'on ne manipulait que des représentations textuelles.

2.1 Scanner un flux de données

Dans cette partie, nous allons exploiter des données contenues dans un fichier en complétant la méthode chargerFormatTexte(File f). Examiner le fichier test1.txt contenant une série de nombre de type double.
Il va être nécessaire d'analyser ce fichier c'est-à-dire récupérer chaque nombre pour construire la liste des points correspondants. La classe Scanner du package java.util permet de réaliser simplement cela. Vous utiliserez le cas le plus élémentaire consistant à utiliser la méthode "nextDouble". A la lecture de la spécification de Scanner, vous constaterez qu'il est possible d'acquérir aisément des données formatées de manière plus sophistiquée.

Réalisez la susdite méthode en construisant pour chaque pair de nombres le point cartésien correspondant et ajouter ce point dans la liste listeDePoints. Pensez à générer des messages d'erreurs lorsque cela semble nécessaire. Vous utiliserez comme dans la première partie un FileReader pour faire l'acquisition.

Compléter en réalisant la méthode sauverFormatTexte(File f) qui permet de sauvegarder selon ce format.

2.2 Générer des listes de PointCartesien

Pour tester différentes situations, on souhaite pouvoir engendrer des collections de PointCartesien. Réalisez la méthode genererListeDePoints(int n) qui admet en paramètre le nombre de points cartésiens à construire. Pour cela, vous utiliserez la fonction random de la classe Math pour produire des valeurs aléatoires.

2.3 Calculer le coût

En utilisant la classe Counter fourni dans le package jus.util, calculer le temps nécessaire pour réaliser l'acquisition d'un fichier avec la méthode chargerFormatTexte(File f). Réalisez une campagne de tests pour établir l'évaluation du coût moyen d'une acquisition.

2.4 Optimisation

Décrivez et effectuez les modifications permettant d'intégrer un BufferedInputStream dans votre solution. Refaites une campagne de tests et comparer les résultats obtenus avec les précédents.

3. Manipulations de fichiers quelconques

3.1 Création de fichiers binaires

On souhaite sauvegarder (et restaurer) des collections de PointCartesien en sauvegardant les représentations binaires des attributs (abscisse et ordonnée) de chacun des points c'est-à-dire conserver dans un fichier les représentations binaires des valeurs de types primitifs. A l'aide d'un DataOutputStream (resp. DataInputStream) réalisez les méthodes sauverFormatPrimitif(File f) et chargerFormatPrimitif(File f).

3.2 Création de fichiers de sérialisation

Le concept de sérialisation permet de lire ou d'écrire des objets (instance d'une classe). Il ne s'agit pas, lorsqu'il s'agit d'écrire un objet, de donner une représentation textuelle d'un objet, mais de donner une représentation binaire. Cette représentation bien que propriétaire sera évidemment indépendante de la plateforme utilisée donc portable. On désire pouvoir sauvegarder et restaurer à l'aide d'un fichier une instance d'une collection de PointCartesien.

Quelle propiété doit avoir la classe PointCartesien pour que la sérialisation fonctionne ?
A l'aide des classes ObjectOutputStream et ObjectInputStream complétez les méthodes sauverFormatObjet(File f) et chargerFormatObjet(File f).

3.2 Etude de la taille des fichiers

A l'aide d'une campagne de tests, donnez une analyse du coût de mémoire secondaire nécessaire au stockage selon le format.

4. Protocole d'analyse des coûts

4.1 Comparaison des coûts des différents formats

Pour étudier les différents formats, nous vous proposons d'élaborer un programme de test qui va établir une matrice des coûts des 3 variantes que vous avez précédemment réalisées. Ces coûts seront réalisés sur l'acquisition des données (chargerFormatX). Pour cela, vous allez réaliser une nouvelle classe TestEvaluation qui hérite de TestIO.

Taille Formats
  Textuel Primitif Objet
1      
2      
4      
8      
16      
32      
     

Afin d'exploiter efficacement cet ensemble de données, on vous propose de construire un fichier au format d'échange Excel. Chaque colonne est représentée par le séparateur de tabulation (\t). et chaque ligne par le séparateur de ligne (\n).

Réalisez dans la classe TestEvaluation la méthode evaluation1() qui met en œuvre ce protocole en suivant une échelle exponentielle pour le nombre de point considéré. On fera démarrer le décompte à une valeur qui produit un résultat significatif.

4.2 Comparaison des coûts avec ou sans bufferisation

Complétez la classe TestEvaluation avec une méthode evaluation2() qui permet un chargement textuel (méthode "charger") en prenant en compte trois cas : sans bufferisation, avec une bufferisation à 8k (le standard) et une bufferisation à 256k.