Elixir File IO

Welcome to a tutorial on File IO in Elixir.

in general, File IO is an integral part of any programming language, because it allows the language to interact with the files on the file system. We will learn about two modules of File IO (Path and File).

 

The Path Module

The path module is a very small module typically considered a helper module for filesystem operations. It functions majorly in the File module expect paths as arguments, and those paths will be regular binaries. 

Also, the Path module provides facilities for working with such paths. Therefore, making use of functions from the Path module as opposed to just manipulating binaries is preferred since the Path module takes care of different operating systems transparently. However, it is observed that Elixir will automatically convert slashes (/) into backslashes () on Windows when performing file operations. Check out the example below.

IO.puts(Path.join("foo", "bar"))

The output is:

foo/bar

In addition, the path module provides so many methods. These methods are commonly used when performing lots of file manipulation operations. You can check them out yourself.

 

The File Module

The file module contains functions that make it possible to open files as IO devices. However, files are opened in binary mode, by default, and require developers to use the specific IO.binread and IO.binwrite functions from the IO module. Check out the example below on to create a file called newfile and then write some data to it.

{:ok, file} = File.read("newfile", [:write]) 
# Pattern matching to store returned stream
IO.binwrite(file, "This will be written to the file")

Now, when we go to open the file we just wrote into, the content will be displayed in the following way:

This will be written to the file 

Let’s learn how to use the file module in the session below.

 

Opening a file

The code below can be used to open a file.

{:ok, file} = File.open("newfile")
file = File.open!("newfile")

Below are highlights of the difference between the File.open function and the File.open!() function.

  • The File.open function returns a tuple always: If a file is successfully opened, it returns the first value in the tuple as :ok and the second value is literal of type the io_device. But, if an error is caused, it will return a tuple with the first value as :error and the second value as the reason.
  • The File.open!() function will return an io_device if a file is successfully opened otherwise it will raise an error. 

Note that, this is the pattern followed in all of the file module functions we are going to discuss in this tutorial.

Also, we can specify the modes in which we want to open this file. Thus, to open a file as read-only and in utf-8 encoding mode, we can use the code below.

file = File.open!("newfile", [:read, :utf8])

 

Writing to a File

There are two ways to write to files. The first one involves using the write function from the File module. This is shown below.

File.write("newfile", "Hello")

Note that, the above should not be used when making multiple writes to the same file. Every time this function is called, a file descriptor is opened and a new process is spawned to write to the file. Therefore, if you are doing multiple writes in a loop, open the file via File.open and write to it using the methods in the IO module. Check out the example below to understand better.

#Open the file in read, write and utf8 modes. 
file = File.open!("newfile_2", [:read, :utf8, :write])

#Write to this "io_device" using standard IO functions
IO.puts(file, "Random text")

Also, you can use other IO module methods such as IO.write and IO.binwrite to write to files opened as io_device.

 

Reading from a File

There are two ways to read from files. The first one is to use the read function from the File module. This is shown below.

IO.puts(File.read("newfile"))

Now, when running this code, a tuple is obtained with the first element as :ok and the second one as the contents of newfile

Also, we can use the File.read! function to get the contents of the files returned to us.

 

Closing an Open File

Anytime we open a file using the File.open function, after we are done using it, we should close it using the File.close function:

File.close(file)