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.
Programming in Lua | ||
Part III. The Standard Libraries Chapter 21. The I/O Library |
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.1411Avoid 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") --> helloLuaHiUnlike
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 |
num | reads 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 fileAs 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 endHowever, 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") endThis 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)) endIn 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.
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |