◆ pipe や read をしなくても作った時点でファイルの読み取りが始まる

fs.createReadStream(...) を使い ReadStream を作った時点でファイルのオープンや読み込みは始まってるものと思っていました
ですが ライブラリを見ていると とりあえず ReadStream までは作って あとからいらなかったのでやっぱり何もせずに捨てるみたいなことをしてるのがありました
作った時点では読み込むファイルを指定しているだけで 実際にオープンや読み込みをしていないのであれば別にいいと思いますけど ファイルアクセスしてるならとりあえず作るのはムダが多くやめてほしいところです

こうも当たり前のように使われてるともしかして作るだけだとファイルにはまだアクセスしてなかったりするのでしょうか?
自信がなくなってきたので調べてみました

ソースコードを見てみるとやっぱり open や read はしてそうです
コード上で見るのは複雑なので実際に動かして試してみます

fs.createReadStream の返り値は ReadStream 型です
fd プロパティにはファイルディスクリプタ
bytesRead プロパティには読み取ったバイト数が入っています

> const f = fs.createReadStream("./example.txt")
> f.fd
4
> f.bytesRead
13271

普通にファイルを開いて読み取りをしていますね

引っ掛かりそうなところもあってファイルのオープンや読み取りは非同期で行われます
なので単に fs.createReadStream(...) を REPL で実行してその返り値を見ると……

> fs.createReadStream("./example.txt")
ReadStream {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 65536,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: null,
ended: false,
endEmitted: false,
reading: false,
sync: true,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: true,
emitClose: false,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null
},
readable: true,
_events: [Object: null prototype] { end: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
path: './example.txt',
fd: null,
flags: 'r',
mode: 438,
start: undefined,
end: Infinity,
autoClose: true,
pos: undefined,
bytesRead: 0,
closed: false
}
>

このように fd は null で bytesRead も 0 です
これを見るとファイルを開いてないように見えなくもないですね

結果を変数に入れてすぐにもう一度アクセスすれば fd も bytesRead も読み取った後の数値が入っています