Ceci est une ancienne révision du document !
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.