Stream API/specs: File.stream! vs IO.stream

File.stream! has a line that’s easy to miss in the docs:

Operating the stream can fail on open for the same reasons as File.open!/2

“Operating” is the key part - you can File.stream! things that don’t exist, and you won’t get the exception until something forces the stream.

For instance:

iex(1)> File.stream!("nosuchfile.txt")

%File.Stream{
  line_or_bytes: :line,
  modes: [:raw, :read_ahead, :binary],
  path: "nosuchfile.txt",
  raw: true
}

iex(2)> File.stream!("nosuchfile.txt") |> Enum.to_list()

** (File.Error) could not stream "nosuchfile.txt": no such file or directory
    (elixir 1.13.0) lib/file/stream.ex:83: anonymous fn/3 in Enumerable.File.Stream.reduce/3
    (elixir 1.13.0) lib/stream.ex:1517: anonymous fn/5 in Stream.resource/3
    (elixir 1.13.0) lib/enum.ex:4143: Enum.reverse/1
    (elixir 1.13.0) lib/enum.ex:3488: Enum.to_list/1

IO.stream can’t fail in any of these ways since it takes either a PID (that you’d get from calling File.open! and possibly getting an exception) or an atom (to refer to stdio), so it doesn’t get a !.

1 Like