Bonjour. Dans cette séquence nous allons parler de la
bibliothèque de Stream qui est fournie de base avec Pharo.
Nous verrons ce que sont les streams et comment les
utiliser, et dans quels cas ils peuvent être utiles.
Alors qu'est-ce qu'un stream ?
Un stream, c'est un objet qui permet
d'itérer sur une séquence d'éléments.
Cette séquence, ça peut être une collection en mémoire,
ça peut être un flux réseau, ça peut être un fichier
ou autres. Un stream garde en mémoire la
position courante, et au fur à mesure de l'utilisation du
stream on va pouvoir avancer ou reculer pour pouvoir lire
ou écrire des éléments dans le stream.
Un aperçu de l'API des streams.
Pour créer un stream, il y a quelques objets sur lesquels
on peut utiliser les messages readStream et writeStream,
pour créer des streams à partir de ces objets-là.
Par exemple à partir d'un fichier ou à partir d'une
collection on peut créer des streams de cette façon-là.
Ce message-là, "streamContents" s'envoie à une collection
et prend un block en paramètre qui reçoit un stream.
Et l'utilisation de ce stream au sein de ce block là va
créer une collection qui sera finalement retournée par la
méthode. On verra l'utilisation de cette méthode-là à la fin.
Dans ces cas-là on demande directement à une classe de
streams, soit readStream, soit writeStream, soit
rewriteStream, de créer une nouvelle instance par rapport à une collection.
Les 3 méthodes qui sont là permettent de lire des
éléments, donc un ou plusieurs jusqu'à une certaine limite.
Et les 2 éléments qui sont là permettent d'écrire un
élément ou une collection d'éléments dans le stream.
Alors voici quelques exemples permettant de lire dans un stream.
Première étape, on crée un stream.
Ici, on crée un stream en lecture à partir d'une collection.
Cette collection contient les lettres de l'alphabet entre
A à F, donc avec un caractère par élément dans la collection.
On créé un stream sur cette collection-là et on va
regarder les caractères un par un.
Une fois qu'on a notre stream, la première chose qu'on
peut faire, c'est envoyer le message next qui va nous
retourner l'élément juste après la position courante.
Dès l'initialisation du stream, la position courante c'est
0 donc on se situe au début du stream, donc next retourne
au début le premier élément, c'est-à-dire A.
Si j'appelle next à ce moment-là je vais obtenir B, puis
C, puis D, et caetera, un par un en appelant next, next,
next on fait évoluer la position d'un cran à chaque fois.
Si j'appelle next une première fois et que j'obtiens A,
ensuite je peux envoyer le message upTo et un élément,
et cette méthode-là va me retourner tous les éléments
entre la position courante et l'élément que j'ai passé en paramètre.
Donc là si avant j'avais A, je me situe en position 1 et
si j'envoie le message upTo D, il va me retourner tout ce
qu'il y a entre la position courante et D, c'est-à-dire B et C.
D est consommé par le stream, c'est-à-dire que maintenant
le stream se situe juste après D mais D n'est pas retourné.
Stream position nous donne la position en cours.
La position commence à 0.
0, c'est avant le premier élément, donc 0, 1, 2, 3,
4, on se situe bien juste avant le E et après le D.
À ce moment-là si j'envoie le message upToEnd au stream,
je vais obtenir tous les éléments qui se situent entre la
position courante et la fin du stream, c'est-à-dire E et
F. Donc on voit que le stream maintient une position
courante que je peux faire avancer grâce à quelques méthodes.
De la même façon on peut écrire dans un stream.
La première étape encore une fois, c'est créer le stream.
Array new: 6 me permet de créer un tableau vide mais de taille 6.
J'envoie le message writeStream dessus pour créer un
stream sur ce tableau-là, de façon à pouvoir remplir le
tableau petit à petit grâce à mon stream.
Je stocke ce stream dans la variable stream et je
commence par envoyer le message nextPut 1, qui prend un
élément et ajoute cet élément en position courante dans le stream.
Maintenant, mon tableau contient un 1 suivi de 5 cases vides.
Le message nextPutAll, quant à lui, prend une collection
d'objets à mettre les uns après les autres dans le stream.
Après l'envoi de ce message nextPutAll à mon stream, j'obtiens
le tableau qui contient un résultat de mon nextPut
précédent suivi de 4, 8, 2, 6, 7,
résultats du nextPutAll.
Donc les streams sont particulièrement utiles et
efficaces pour lire et écrire dans les collections d'objets.
Je peux aussi lire et écrire dans des fichiers.
Là, je montre un exemple de comment écrire dans un
nouveau fichier qui n'existe pas encore.
Dans la chaîne de caractères ici j'indique le nom du fichier.
En envoyant à une chaîne de caractères le message
asFileReference, je créé une référence vers un fichier.
Là c'est un fichier qui n'existe pas encore mais je peux
quand même avoir une référence dessus.
J'ai une référence vers un fichier et le point txt et j'envoie
le message write Stream sur ce fichier
histoire d'avoir un stream en écriture vers ce fichier
qui n'existe pas encore. Dès qu'on va écrire dans le
stream, le fichier va être recréé.
Maintenant que j'ai mon stream, j'envoie le message
nextPutAll avec une chaîne de caractères et ce message
nextPutAll va écrire caractère après caractère chaque
élément de ma chaîne de caractères.
Il va écrire le H, puis le E, puis le L, et cetera.
A la fin, je
ferme mon stream pour indiquer au système d'exploitation
que j'ai fini d'écrire dans le fichier, et qu'il peut lui
écrire l'ensemble sur le support de stockage et fermer le
pointeur sur le fichier.
Maintenant que j'ai écrit dans ce fichier, je peux avoir envie de le lire.
De la même façon, j'ai le nom du fichier sous forme d'une
chaînes de caractères, asFile Reference qui me
permet de créer une référence vers ce fichier-là,
et read stream qui me permet d'ouvrir un flux en lecture,
qui permet d'ouvrir un stream en lecture sur ce fichier-là.
Avec next, je récupère le premier élément dans le stream.
J'avais écrit "Hello Pharo", le premier élément, c'est H, H majuscule.
Et avec upToEnd, je récupère tous les caractères entre la
position courante, c'est-à-dire juste après le H avant le
E et jusqu'à la fin du stream, jusqu'à la fin du fichier.
J'obtiens'ello Pharo'sans le H puisque je l'ai déjà
récupéré grâce au next précédent.
On peut créer des collections en utilisant des streams.
Ça c'est très utile quand on veut créer des collections
et qu'il nous faut du code pour choisir ce qu'on va
mettre dans la collection petit à petit.
Là, je veux créer une OrderedCollection
en envoyant des messages à un stream.
À partir de ma classe OrderedCollection, je fais une
nouvelle instance, j'en fais un flux en écriture
et avec le message next put, j'ajoute l'élément 1 dans mon stream.
Maintenant quand je vais faire streamContents, je vais
obtenir une instance de la classe OrderedCollection qui
contient uniquement la valeur 1.
Ces 3 expressions peuvent s'écrire plus simplement comme
on le voit en-dessous. En envoyant le message
"streamContents" à la classe de collection qui nous
intéresse, donc ici c'est OrderedCollection, j'envoie ce
message "streamContents" à OrderedCollection, je lui
passe en paramètre un block qui prend un stream en paramètre.
Au sein de ce block, je vais utiliser le stream pour
remplir ma collection petit à petit et quand le block se
termine j'obtiens ma collection.
Dans le block, je fais "stream nextPut 1", j'ajoute
1 dans mon stream qui va l'ajouter dans la collection.
Quand "streamContents" quitte, donc quand l'ensemble de
cette expression se termine, je vais obtenir une
OrderedCollection qui contient 1.
StreamContents c'est utile pour créer des collections à partir de rien.
Dans cette séquence, nous avons découvert l'API de stream.
Il y a énormément de méthodes dans cette API que je vous
invite à aller découvrir en naviguant dans les classes
grâce au navigateur de codes Nautilus.
Un stream peut lire et écrire dans des collections d'éléments
en mémoire, dans des fichiers, sur le réseau et d'autres éléments encore.
Un stream a toujours une position courante, c'est important.
La position courante sépare les éléments du passé des
éléments du futur, et en fait évoluer cette position
courante à chaque fois qu'on va vouloir lire ou écrire dans le flux.
Enfin, les streams peuvent servir à créer des nouvelles collections.