files without streams). We’ll use file streams to demonstrate how to create read and
write streams, and how to pipe streams to one another.
We’ll start by creating a write stream and writing to it:
const
ws
=
fs
.
createWriteStream
(
'stream.txt'
, {
encoding
:
'utf8'
});
ws
.
write
(
'line 1\n'
);
ws
.
write
(
'line 2\n'
);
ws
.
end
();
The end method optionally takes a data argument that is equivalent
to calling write. Thus, if you’re sending data only once, you can
simply call end with the data you want to send.
Our write stream (
ws
) can be written to with the
write
method until we call
end
, at
which point the stream will be closed, and further calls to
write
will produce an
error. Because you can call
write
as many times as you need before calling
end
, a
write stream is ideal for writing data over a period of time.
Similarly, we can create a read stream to read data as it arrives:
const
rs
=
fs
.
createReadStream
(
'stream.txt'
, {
encoding
:
'utf8'
});
rs
.
on
(
'data'
,
function
(
data
) {
console
.
log
(
'>> data: '
+
data
.
replace
(
'\n'
,
'\\n'
));
});
rs
.
on
(
'end'
,
function
(
data
) {
console
.
log
(
'>> end'
);
});
In this example, we’re simply logging the file contents to the console (replacing new‐
lines for neatness). You can put both of these examples in the same file: you can have
a write stream writing to a file and a read stream reading it.
Duplex streams are not as common, and are beyond the scope of this book. As you
might expect, you can call
write
to write data to a duplex stream, as well as listen for
data
and
end
events.
Because data “flows” through streams, it stands to reason that you could take the data
coming out of a read stream and immediately write it to a write stream. This process
is called piping. For example, we could pipe a read stream to a write stream to copy
the contents of one file to another:
const
rs
=
fs
.
createReadStream
(
'stream.txt'
);
const
ws
=
fs
.
createWriteStream
(
'stream_copy.txt'
);
rs
.
pipe
(
ws
);
296 | Chapter 20: Node