Lua’s I/O library has a simple model based on current input/output files and a complete model based on explicit file handles. Explicit handles are clearer for all but tiny scripts.
Reading a file
1 | local file, err = io.open("notes.txt", "r") |
file:read("l") reads a line without its newline, "L" keeps the newline in supported versions, "a" reads the remainder, and "n" reads a number. Avoid reading an unbounded file all at once when its size is not trusted.
io.lines(filename) returns an iterator and automatically closes the file at end-of-file:
1 | for line in io.lines("notes.txt") do |
Writing safely
1 | local output, err = io.open("result.txt", "w") |
Modes include r, w, and a, optionally combined with + and binary b. Opening with w truncates an existing file. For important data, write to a temporary file in the same directory, flush and close it, then replace the destination using an operating-system-appropriate atomic operation.
Standard streams and positioning
io.stdin, io.stdout, and io.stderr are standard handles. file:seek("set", offset), "cur", and "end" reposition seekable files. Text-mode offsets may not behave like raw byte offsets on every platform.
Always handle open, read, write, and close failures. Lua’s garbage collector may eventually close an abandoned file, but deterministic closure avoids descriptor exhaustion and ensures buffered output is reported promptly.