Elixir - File IO



File IO is an integral part of any programming language as it allows the language to interact with the files on the file system. In this chapter, we will discuss two modules − Path and File.

The Path Module

The path module is a very small module that can be considered as a helper module for filesystem operations. The majority of the functions in the File module expect paths as arguments. Most commonly, those paths will be regular binaries. The Path module provides facilities for working with such paths. Using functions from the Path module as opposed to just manipulating binaries is preferred since the Path module takes care of different operating systems transparently. It is to be observed that Elixir will automatically convert slashes (/) into backslashes (\) on Windows when performing file operations.

Let us consider the following example to further understand the Path module −

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

When the above program is run, it produces the following result −

foo/bar

There are a lot of methods that the path module provides. You can have a look at the different methods here. These methods are frequently used if you are performing many file manipulation operations.

The File Module

The file module contains functions that allow us to open files as IO devices. By default, files are opened in binary mode, which requires developers to use the specific IO.binread and IO.binwrite functions from the IO module. Let us create a file called newfile and 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")

If you go to open the file we just wrote into, content will be displayed in the following way −

This will be written to the file 

Let us now understand how to use the file module.

Opening a file

To open a file, we can use any one of the following 2 functions −

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

Let us now understand the difference between the File.open function and the File.open!() function.

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

  • The File.open!() function on the other hand will return a io_device if file is successfully opened else it will raise an error. NOTE: This is the pattern followed in all of the file module functions we are going to discuss.

We can also specify the modes in which we want to open this file. To open a file as read only and in utf-8 encoding mode, we use the following code −

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

Writing to a File

We have two ways to write to files. Let us see the first one using the write function from the File module.

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

But this should not be used if you are making multiple writes to the same file. Every time this function is invoked, a file descriptor is opened and a new process is spawned to write to the file. If you are doing multiple writes in a loop, open the file via File.open and write to it using the methods in IO module. Let us consider an example to understand the same −

#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")

You can use other IO module methods like IO.write and IO.binwrite to write to files opened as io_device.

Reading from a File

We have two ways to read from files. Let us see the first one using the read function from the File module.

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

When running this code, you should get a tuple with the first element as :ok and the second one as the contents of newfile

We can also use the File.read! function to just get the contents of the files returned to us.

Closing an Open File

Whenever you open a file using the File.open function, after you are done using it, you should close it using the File.close function −

File.close(file)
Advertisements