Hello. In this course, I'll talk about the stream library.
It's a basic feature of Pharo.
We'll see what streams are, how to use them, and when they can be useful.
What is a stream?
It's an object
that enables to iterate over a collection of elements,
a sequence of elements.
This sequence could be a collection in memory,
a network flow, a file, etc.
A stream keeps the current position in memory.
As you use the stream, you can move forward or backward
to read from or write elements to the stream.
An overview of the streams' API.
To create a stream, there are a few objects
over which you can use the messages readStream and writeStream
to create streams
(from a file or a collection, for instance).
You can create streams this way.
This message, streamContents:, is sent to a collection
and takes a block as a parameter, which receives a stream.
The use of a stream within this block creates a collection
the method will eventually return.
We'll see how to use this method in the end.
In this case, you directly ask a class,
either readStream, writeStream, or (Read/Write)Stream,
to create a new instance over a collection.
These three methods can read one or several elements
up to a point.
These two elements
write an element or a collection of elements to the stream.
These are a few examples through which you can read from a stream.
First, create a stream.
I'm creating a readStream from a collection.
The collection contains all letters between a and f.
There's one character for every element in the collection.
Create a stream over the collection. Let's look at the characters one by one.
Once the stream is ready,
you may start by sending the message next
which will return an element right after the current position
when the stream is initialized.
The current position is 0, at the beginning of the stream.
next returns the first element, which is a.
If I call next at this time,
I'll get a then b then c, one at a time.
By calling next, the position moves by one row at a time.
If I call next once and get a,
I can send the message upTo: and one element.
This method returns all the elements between the current position
and the element I placed as parameter.
With a, I'm in position 1.
If I send upTO: $d,
it returns what's between the current position and d:
b and c.
d is consumed by the stream.
It means the stream is now located right after d.
d isn't returned.
stream position returns the current position.
The position starts at 0.
0 is located before the first element: 0, 1, 2, 3, 4.
We're right before e and after d.
Now if I send the message upToEnd to the stream, I'll get all the elements
located between the current position and the end of the stream:
that's e and f.
The stream maintains a current position I can move forward
thanks to a few methods.
You can also write to a stream.
The first step is to create the stream.
With Array new: 6, I create a size-6 array.
I send the message writeStream to create a stream on the array
to be able to gradually fill it in thanks to the stream.
I store the stream in the variable stream.
I first send the message nextPut: 1
which takes one element and adds it to the current position in the stream.
My array now contains 1 followed by five empty cells.
The message nextPutAll: takes a collection of objects
which are appended to the stream.
After sending nextPutAll: to the stream,
I get an array that contains 1,
the result of the previous nextPut:,
followed by 4 8 2 6 7,
the result of nextPutAll:.
Streams are especially useful and efficient
to read from and write to object collections.
I can also write to and read from files.
I'm giving an example of how to write
to a new file that doesn't exist yet.
In the stream, I type the name of the file.
By sending a stream with the message asFileReference,
I create a reference to a file.
This is a file that doesn't exist yet, but I can still get a reference to it.
I have a reference to a file, hello.txt.
I send the message writeStream
to the file
in order to get a write stream related to this non-existent file.
As soon as you write to the stream, the file is created.
Now that I have a stream, I send the message nextPutAll: with a string.
This message writes, one character at a time, each element of the string.
"h" then "e" then "l", etc.
In the end,
I close the stream
to tell the operating system I'm done writing in the file
and that it can write everything to the storage system
and close the file pointer.
Now that I've written in the file, I can read it.
The file name
is displayed as a string.
With asFileReference, I can create a reference to this file.
With readStream,
I can open a read flow,
a read stream when it comes to this file.
With next, I get the first element of the stream.
I wrote "Hello Pharo!". The first element is "H".
With upToEnd, I get all the characters
between the current position, after "H" and before "e",
and the end of the file.
I get "ello Pharo!" without "H"
as I already got it thanks to next.
One can create collections using streams.
It's useful when you want to create collections
and you need code to choose what to gradually include in them.
I want to create an OrderedCollection
by sending messages to a stream.
From the class OrderedCollection,
I start a new instance
which I turn into a writeStream.
Thanks to the message nextPut:, I add 1 in the stream.
If I type stream contents,
I get an instance of the class OrderedCollection
which contains the value 1 only.
These three expressions can be simplified, as shown below.
You may send the message streamContents:
to the class we're interested in, which is OrderedCollection.
I send streamContents: to OrderedCollection.
I pass it a block as a parameter which takes a stream as a parameter.
Within the block, I use the stream to gradually fill in the collection.
When the block is over, I get a collection.
In the block, I type stream nextPut: 1.
I add 1 to the stream.
It gets added to the collection.
When streamContents: quits, when this expression is over,
I'll get an OrderedCollection containing 1.
streamContents: is useful to create collections from scratch.
In the course, we learned about stream's API.
There are many methods you should learn about by exploring the classes
thanks to Nautilus code navigator.
A stream can read from and write to collections in memory,
files, the network, etc.
A stream maintains a current position.
The current position separates the past elements from the future elements.
Whenever you write to or read from the flux, the current position changes.
Streams can also help create new collections.