iodata and chardata

In all of the examples above, we used binaries when writing to files. In the chapter “Binaries, strings and char lists”, we mentioned how strings are simply bytes while char lists are lists with code points.

The functions in IO and File also allow lists to be given as arguments. Not only that, they also allow a mixed list of lists, integers and binaries to be given:

iex> IO.puts 'hello world'
hello world
:ok
iex> IO.puts ['hello', ?\s, "world"]
hello world
:ok

However, this requires some attention. A list may represent either a bunch of bytes or a bunch of characters and which one to use depends on the encoding of the IO device. If the file is opened without encoding, the file is expected to be in raw mode, and the functions in the IO module starting with bin* must be used. Those functions expect an iodata as argument; i.e., they expect a list of integers representing bytes and binaries to be given.

On the other hand, :stdio and files opened with :utf8 encoding work with the remaining functions in the IO module. Those functions expect a char_data as an argument, that is, a list of characters or strings.

Although this is a subtle difference, you only need to worry about these details if you intend to pass lists to those functions. Binaries are already represented by the underlying bytes and as such their representation is always “raw”.

This finishes our tour of IO devices and IO related functionality. We have learned about four Elixir modules - IO, File, Path and StringIO - as well as how the VM uses processes for the underlying IO mechanisms and how to use chardata and iodata for IO operations.