• Aucun résultat trouvé

Programmation objet avancée

N/A
N/A
Protected

Academic year: 2022

Partager "Programmation objet avancée"

Copied!
23
0
0

Texte intégral

(1)

Programmation objet avancée

Les entrées/sorties

(2)

Plan

Définition.

Les 3 questions.

Principes généraux d'utilisation.

Principes « réels » d'utilisation.

La sérialisation.

(3)

Définition

flux : représentation abstraite d'une suite de données à destination ou en provenance d'une ressource (fichier, périphérique, mémoire, …)

Þ notion adaptée à la programmation objet Þ flux représenté par une classe

type des données (du plus au moins simple) :

octets,

caractères,

(4)

Définition

Dans la plupart des langages, on différencie :

flux de lecture = lecture des données en provenance de la ressource,

flux d'écriture = écriture des données à destination de la ressource.

Remarque : normalement, la classe de flux ne dépend que du type de données et pas de la ressource.

Ce n'est pas le cas en Java !

Þ règles au cas par cas mais simples à choisir

(5)

Les 3 questions

Pour choisir les bonnes classes de flux, adaptées au problème, on se pose 3 questions :

quelle ressource (fichier, mémoire, socket, …) est employée ?

quels types de données doivent être lu/écrits ?

dans quel sens (lecture, écriture) va le flux ?

Remarque : dans 99 % des cas, ressource = fichier ou socket

(6)

Principes généraux d'utilisation

1. obtenir un objet représentant un flux d'octets : fichiers : FileInputStream, FileOutputStream

socket : InputStream, OutputStream

Remarques :

lecture = Input, écriture = Output

pour fichiers : instanciation explicite

FileInputStream fis = new FileInputStream("toto.txt");

pour sockets : appel à une méthode de la classe Socket

InputStream is = sock.getInputStream();

(7)

Principes généraux d'utilisation

2. encapsuler l'objet flux d'octets dans une classe qui

« convertit » les octets en données plus structurées.

Þ objet flux = paramètre du constructeur de la classe encapsulante

Les classes encapsulantes dépendent du type à lire/écrire :

caractères : InputStreamReader, OutputStreamWriter

types primaires : DataInputStream, DataOutputStream

objets : ObjectInputStream, ObjectOutputStream

(8)

Principes généraux d'utilisation

Exemple n°1 : lecture caractères dans fichier

Remarque : possibilité écriture « condensée »

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

isr.close();

System.exit(1);

}

isr = new InputStreamReader(new FileInputStream("toto.txt"));

(9)

Principes généraux d'utilisation

Exemple n°2 : écriture objet sur socket

Socket sock = ...;

OutputStream os = null;

ObjetOutputStream oos = null;

try {

os = sock.getOutputStream(); // flux octets sur socket oos = new ObjectOutputStream(os); // encapsulation

...

}catch(IOException e) {

System.out.println("pb ecriture socket : "+e.toString());

oos.close();

System.exit(1);

(10)

Principes généraux d'utilisation

Remarques :

flux d'octets/caractères : méthodes de lecture/écriture de tableaux d'octets/caractères Þ pas forcément pratique,

flux objets : méthodes de lecture/écriture d'octets, caractères, données primaires et objets = réunion de toutes les possibilités,

écriture avec un type de flux Þ lecture avec le même type.

Exemple :

écriture d'un double avec un ObjectOutputStream + lecture avec

DataInputStream Þ ERREUR !

(11)

Principes généraux d'utilisation

Remarques :

gros volumes de données transmis en petits bouts Þ lectures/écritures peu performantes,

un même flux peut être encapsulé dans plusieurs classes,

« fermer » un flux = couper l'accès à la ressource Þ si plusieurs flux existants, tous sont fermés.

(12)

Principes « réels » d'utilisation

simplicité = utiliser un seul type de flux, couvrant tous les besoins de l'application,

Þ en général, flux objet sauf si uniquement du texte

simplicité = classes « auto » encapsulantes pour les fichiers

FileReader, FileWriter

possibilités = classes « pratiques » pour manipuler le texte :

BufferedReader, PrintWriter/PrintStream

performance = classes de bufferisation (mise en tampon) :

BufferedInputStream, BufferedOutputStream

Þ lecture/écriture quand volume cumulé suffisant

(13)

Principes « réels » d'utilisation

Exemples n° 3, 4, 5 :

lecture ligne de texte dans fichier

BufferedReader br = new BufferedReader(new FileReader("f.txt"));

String line = br.readLine();

PrintWriter pw = new PrintWriter("toto.txt");

int i=5; Date d= new Date(2013, 9, 13);

pw.println("nous sommes le " +d+ "et il fait " +i+ "degrés");

ObjectOutputStream oos = new ObjectOutputStream(

new BufferedOutputStream(

écriture texte dans fichier

écriture bufferisée sur une socket

(14)

Principes « réels » d'utilisation

Exemple n°6 : lecture naïve d'un fichier binaire

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}

catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

isr.close();

System.exit(1);

}

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}

catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

isr.close();

System.exit(1);

}

import java.io.* ; class LitFichier {

public static void main(String[] args) { File fich = new File(args[0]);

byte[] tab = new byte[fich.length()];

FileInputStream fis = null;

try {

fis = new FileInputStream(fich);

fis.read(tab,0,fich.length());

}

catch(IOException e) {

System.out.println("pb lecture fichier "+e.toString());

System.exit(1);

} }}

(15)

Principes « réels » d'utilisation

Exemple n°6 bis : lecture+envoi fichier sur une socket

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}

catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}

catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

Socket sock = null;

FileInputStream fis = null;

byte[] tab = new byte[4096];

int nbLu;

try {

sock = new Socket(...);

OutputStream os = sock.getOutputStream();

fis = new FileInputStream(...);

while( (nbLu = fis.read(tab,0,4096)) >= 0) { os.write(tab,0,nbLu);

}

(16)

Principes « réels » d'utilisation

Remarques :

Méthodes du type XXXX(...[] buf, int offset, int size) :

offset est la première case de buf à être remplie/lue,

size est le nombre de cases à lire/écrire.

Sauf problème système/dépassement de tableau, les méthodes d'écriture écrivent autant d'octets/caractères que demandé.

certaines méthodes d'écriture sont par défaut bufferisées (par exemple, celles de ObjectOutputStream).

Pour forcer l'écriture des données en buffer : flush().

(17)

Principes « réels » d'utilisation

Remarques :

lecture par défaut bloquante = s'il n'y a rien à lire, la méthode attend.

ATTENTION ! la lecture prend ce qu'il y a de disponible Þ si demande de N octets, le buffer est rempli avec 0 < M <= N octets.

Par exemple, int read(byte[] buf, int offset, int size) : renvoie le nombre d'octets réellement lus, peut être < size.

(18)

Principes « réels » d'utilisation

Exemple n°7 : lecture d'un fichier texte ligne par ligne

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}

catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

isr.close();

System.exit(1);

}

File fich = new File("toto.txt");

FileInputStream fis;

InputStreamReader isr;

try {

fis = new FileInputStream(fich); // flux d'octets sur fichier isr = new InputStreamReader(fis); // encapsulation

...

}

catch(IOException e) {

System.out.println("pb lecture fichier : "+e.toString());

isr.close();

System.exit(1);

}

import java.io.* ; class LitTexte {

public static void main(String[] args) { BufferedReader br = null;

try {

br = new BufferedReader(new FileReader(args[0]));

String line = br.readLine();

while (line != null) {

System.out.println(line);

line = br.readLine();

} }

catch(IOException e) {

System.out.println("pb lecture fichier "+e.toString());

System.exit(1);

} }

(19)

La sérialisation

objet contient attributs Þ transmettre un objet suppose au minimum de transmettre la valeur de ses attributs.

sérialisation : compactage des valeurs des attributs + informations internes d'un objet, sous forme d'un tableau d'octets.

désérialisation : décompactage d'un tel tableau pour créer un objet.

envoyer/recevoir des objets Þ mettre en place un mécanisme de (dé)sérialisation des objets.

(20)

La sérialisation

En Java, pas besoin d'écrire ces méthodes : le compilateur peut les générer automatiquement.

Þ ajout de l'interface Serializable. Exemple :

class MaClasse { ...

}

class MaClasse implements Serializable { ...

}

Grâce au changement de déclaration, les objets de la classe peuvent être envoyés/reçus sur un flux objet.

Remarque : la plupart des classes de l'API Java sont déjà Serializable.

Þ

(21)

La sérialisation

lecture d'un objet : readObject() renvoie un Object

→ transtyper (= cast) l'objet reçu au bon type Exemple :

MaClasse m = new MaClasse();

ObjectOutputStream oos;

try {

oos = ...;

oos.writeObject(m);

oos.flush();

...

}

MaClasse m;

ObjectInputStream ois;

try {

ois = ...;

m =(MaClasse)ois.readObject();

...

}

catch(IOException e ) { ... }

(22)

La sérialisation

Remarques :

En cas de composition, la (dé)sérialisation ne fonctionne que pour les classes (dé)sérialisables.

La plupart des classes de l'API Java sont sérialisables, notamment les collections Þ lire/écrire une collection d'objets sérialisables = une seule ligne de code.

class B { int i;

}

class A implements Serializable {

B b; // b ne sera pas (dé)sérialisé double d; // d sera (dé)sérialisé }

List<A> l=new ArrayList<A>();

ObjectOutputStream oos=...;

oos.writeObject(l); // OK

class A implements Serializable { ...

}

(23)

La sérialisation

Remarques (bis) :

Le fait d'utiliser un flux objet pour envoyer des types primaires (avec writeInt(), writeDouble(), …) ne fait pas appel aux mêmes principes de sérialisation que les objets.

Cependant, contrairement à DataOutputStream, les types primaires ne sont pas envoyés tels quels mais avec une

« entête » indiquant leur type → relecture obligatoire avec un flux objet.

Qui plus est, l'envoi est bufferisé → flush() pour forcer l'envoi si besoin.

Références

Documents relatifs

Nous arrêterons là notre exposé puisque nos lecteurs se rendent compte que /es conditions mentionnées pour un bon apprentissage de fa lecture sont celles-là même que

Une classe A utilise une autre classe B si elle déclare en son sein une ou plusieurs entités de la classe B et en appelle les méthodes.. On dit aussi que la classe A est cliente de

On appelle type abstrait de données (TAD) un ensemble d'objets caractérisés par les opérations qui leur sont tous applicables... TYPE ABSTRAIT

Fonction C normale qui jouit du privilège d'avoir accès aux membres privés d'une classe.. ✔ On la déclare friend au sein de

Cette implémentation s'est en fait contenté, avec super.clone(); , de faire appel à la méthode clone() héritée de Object , qui crée un objet de la même classe que l'original

- File getParentFile() renvoie un objet File pointant sur le chemin parent de celui de l’objet File courant - boolean isDirectory() indique si l’objet File pointe sur un r´epertoire..

- Lorsqu’il y a 5 % et plus de mots dont la signification est inconnue, le lecteur ne peut comprendre le sens global du texte. - Un mot sur deux qu’on lit est dans

Cette méthode retourne vrai s’il existe une l’intersection ainsi que le point d’intersection faux, dans le cas contraire..  Une classe Droite constituée d’un Point et