This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.


21.1 – The Simple I/O Model

The simple model does all of its operations on two current files. The library initializes the current input file as the process's standard input (stdin) and the current output file as the process's standard output (stdout). Therefore, when we execute something like io.read(), we read a line from the standard input.

We can change those current files with the io.input and io.output functions. A call like io.input(filename) opens the given file (in read mode) and sets it as the current input file. From this point on, all input will come from this file, until another call to io.input; io.output does a similar job for output. In case of errors, both functions raise the error. If you want to handle errors directly, you must use io.open, from the complete model.

As write is simpler than read, we will look at it first. The io.write function simply gets an arbitrary number of string arguments and writes them to the current output file. Numbers are converted to strings following the usual conversion rules; for full control over this conversion, you should use the format function, from the string library:

    > io.write("sin (3) = ", math.sin(3), "\n")
      --> sin (3) = 0.1411200080598672
    > io.write(string.format("sin (3) = %.4f\n", math.sin(3)))
      --> sin (3) = 0.1411
Avoid code like io.write(a..b..c); the call io.write(a,b,c) accomplishes the same effect with fewer resources, as it avoids the concatenations.

As a rule, you should use print for quick-and-dirty programs, or for debugging, and write when you need full control over your output:

    > print("hello", "Lua"); print("Hi")
      --> hello   Lua
      --> Hi
    
    > io.write("hello", "Lua"); io.write("Hi", "\n")
      --> helloLuaHi
Unlike print, write adds no extra characters to the output, such as tabs or newlines. Moreover, write uses the current output file, whereas print always uses the standard output. Finally, print automatically applies tostring to its arguments, so it can also show tables, functions, and nil.

The read function reads strings from the current input file. Its arguments control what is read:
"*all"reads the whole file
"*line"reads the next line
"*number"reads a number
numreads a string with up to num characters

The call io.read("*all") reads the whole current input file, starting at its current position. If we are at the end of file, or if the file is empty, the call returns an empty string.

Because Lua handles long strings efficiently, a simple technique for writing filters in Lua is to read the whole file into a string, do the processing to the string (typically with gsub), and then write the string to the output:

    t = io.read("*all")         -- read the whole file
    t = string.gsub(t, ...)     -- do the job
    io.write(t)                 -- write the file
As an example, the following code is a complete program to code a file's content using the quoted-printable encoding of MIME. In this encoding, non-ASCII characters are coded as =XX, where XX is the numeric code of the character in hexadecimal. To keep the consistency of the encoding, the `=´ character must be encoded as well. The pattern used in the gsub captures all characters with codes from 128 to 255, plus the equal sign.
    t = io.read("*all")
    t = string.gsub(t, "([\128-\255=])", function (c)
          return string.format("=%02X", string.byte(c))
        end)
    io.write(t)
On a Pentium 333MHz, this program takes 0.2 seconds to convert a file with 200K characters.

The call io.read("*line") returns the next line from the current input file, without the newline character. When we reach the end of file, the call returns nil (as there is no next line to return). This pattern is the default for read, so io.read() has the same effect as io.read("*line"). Usually, we use this pattern only when our algorithm naturally handles the file line by line; otherwise, we favor reading the whole file at once, with *all, or in blocks, as we will see later. As a simple example of the use of this pattern, the following program copies its current input to the current output, numbering each line:

    local count = 1
    while true do
      local line = io.read()
      if line == nil then break end
      io.write(string.format("%6d  ", count), line, "\n")
      count = count + 1
    end
However, to iterate on a whole file line by line, we do better to use the io.lines iterator. For instance, we can write a complete program to sort the lines of a file as follows:
    local lines = {}
    -- read the lines in table 'lines'
    for line in io.lines() do
      table.insert(lines, line)
    end
    -- sort
    table.sort(lines)
    -- write all the lines
    for i, l in ipairs(lines) do io.write(l, "\n") end
This program sorts a file with 4.5 MB (32K lines) in 1.8 seconds (on a Pentium 333MHz), against 0.6 seconds spent by the system sort program, which is written in C and highly optimized.

The call io.read("*number") reads a number from the current input file. This is the only case where read returns a number, instead of a string. When you need to read many numbers from a file, the absence of the intermediate strings can make a significant performance improvement. The *number option skips any spaces before the number and accepts number formats like -3, +5.2, 1000, and -3.4e-23. If it cannot find a number at the current file position (because of bad format or end of file), it returns nil.

You can call read with multiple options; for each argument, the function will return the respective result. Suppose you have a file with three numbers per line:

    6.0       -3.23     15e12
    4.3       234       1000001
    ...
Now you want to print the maximum of each line. You can read all three numbers in a single call to read:
    while true do
      local n1, n2, n3 = io.read("*number", "*number",
                                 "*number")
      if not n1 then break end
      print(math.max(n1, n2, n3))
    end
In any case, you should always consider the alternative of reading the whole file with option "*all" from io.read and then using gfind to break it up:
    local pat = "(%S+)%s+(%S+)%s+(%S+)%s+"
    for n1, n2, n3 in string.gfind(io.read("*all"), pat) do
      print(math.max(n1, n2, n3))
    end

Besides the basic read patterns, you can call read with a number n as argument: In this case, read tries to read n characters from the input file. If it cannot read any character (end of file), read returns nil; otherwise, it returns a string with at most n characters. As an example of this read pattern, the following program is an efficient way (in Lua, of course) to copy a file from stdin to stdout:

    local size = 2^13      -- good buffer size (8K)
    while true do
      local block = io.read(size)
      if not block then break end
      io.write(block)
    end

As a special case, io.read(0) works as a test for end of file: It returns an empty string if there is more to be read or nil otherwise.