Lua File I/O
Lua - File I/O
Section titled “Lua - File I/O”Lua’s I/O library provides functions for reading from and writing to files. It offers two main models for file operations: implicit file descriptors (using a default input/output file) and explicit file descriptors (working with specific file objects).
For the examples below, let’s assume we have a sample file named data.txt with the following content:
Hello Lua Learner!This is the second line.End of file.Before running examples that write to this file, ensure you have a backup or are okay with it being modified/overwritten.
Opening and Closing Files
Section titled “Opening and Closing Files”The primary function to open a file is io.open(filename [, mode]).
filename: The name (or path) of the file to open.mode: A string specifying the file access mode. If omitted, the default mode depends on the Lua version and OS but is often read-only.
Common file modes:
| Mode | Description |
|---|---|
"r" | Read mode (default). File must exist. Reading starts at the beginning. |
"w" | Write mode. Creates a new file or truncates an existing file to zero length. Writing starts at the beginning. |
"a" | Append mode. Creates a new file if it doesn’t exist. Writing starts at the end of the file. |
"r+" | Update mode (read and write). File must exist. Reading/writing can occur at any position. |
"w+" | Update mode (read and write). Creates a new file or truncates an existing file. Reading/writing can occur at any position. |
"a+" | Append update mode (read and write). Creates a new file if it doesn’t exist. Reading can occur at any position, writing is always appended. |
You can also append "b" to the mode (e.g., "rb", "wb") to open the file in binary mode, which is important on some systems (like Windows) to prevent translation of newline characters. On Unix-like systems, binary and text modes are usually the same.
If io.open succeeds, it returns a file object (also called a file handle). If it fails (e.g., file not found in "r" mode, permissions error), it returns nil followed by an error message and an error code.
local file, err = io.open("non_existent_file.txt", "r")if not file then print("Error opening file: ", err)else -- Process file file:close()endIt’s crucial to close files using file:close() when you are done with them to release system resources and ensure data is flushed to disk.
Implicit File Descriptors (Standard I/O)
Section titled “Implicit File Descriptors (Standard I/O)”Lua provides default file handles for standard input (io.stdin), standard output (io.stdout), and standard error (io.stderr). Functions like io.read(), io.write(), and print() use these by default.
io.input(file_or_filename) and io.output(file_or_filename) can change the default input/output files.
-- Create data.txt if it doesn't exist with some contentlocal initial_file_setup, err_setup = io.open("data.txt", "w")if initial_file_setup then initial_file_setup:write("Hello Lua Learner!\nThis is the second line.\nEnd of file.\n") initial_file_setup:close()else print("Setup error: ", err_setup) return -- Exit if setup failedend
-- Example using implicit descriptorslocal original_input = io.input() -- Save original default inputlocal original_output = io.output() -- Save original default output
-- Set default input to data.txtlocal file_in, err_in = io.input("data.txt")if not file_in then print("Error setting input: ", err_in)else local first_line = io.read("*l") -- Read a line from default input (now data.txt) print("First line read: ", first_line) io.close(file_in) -- Close the file associated with the default inputend
-- Restore original default inputio.input(original_input)
-- Append to data.txt using default outputlocal file_out, err_out = io.output("data.txt", "a") -- Mode 'a' for append is not standard for io.output, usually opens in write mode -- Better to use explicit file handling for append-- For safety and clarity, let's use explicit file handling for append here:file_out, err_out = io.open("data.txt", "a")if not file_out then print("Error opening for append: ", err_out)else file_out:write("\nAppended via explicit handle.") file_out:close()end
-- Verify appendlocal verify_file, err_verify = io.open("data.txt", "r")if verify_file then print("\n--- Content of data.txt after append ---") print(verify_file:read("*a")) verify_file:close()else print("Error verifying: ", err_verify)end
-- Note: Changing default input/output is less common than explicit file handling.Reading from Files
Section titled “Reading from Files”The file:read(...) method (for explicit file objects) or io.read(...) (for default input) reads data. It accepts one or more format strings:
| Format | Description |
|---|---|
"*n" or "n" | Reads a number. Skips spaces before trying to read. Returns nil if a number cannot be parsed or at EOF. |
"*a" or "a" | Reads the whole file from the current position. Returns an empty string at EOF. |
"*l" or "l" | Reads the next line, discarding the newline character. Returns nil at EOF. |
"*L" or "L" | Reads the next line, keeping the newline character. Returns nil at EOF. |
| number | Reads up to number bytes (a string of that many characters). Returns nil at EOF. |
local file, err = io.open("data.txt", "r")if file then print("\n--- Reading data.txt line by line ---") local line1 = file:read("*l") print("Line 1: ", line1)
local rest_of_file = file:read("*a") print("Rest of file: ", rest_of_file)
file:close()else print("Error reading file: ", err)endThe file:lines() iterator is very convenient for reading a file line by line:
print("\n--- Reading data.txt with file:lines() ---")local file_lines, err_lines = io.open("data.txt", "r")if file_lines then for line in file_lines:lines() do print("Iterator Line: ", line) end file_lines:close() -- lines() iterator does not close the file automatically when file object is passedelse print("Error opening for lines: ", err_lines)end
-- io.lines(filename) opens, iterates, and closes the file automaticallyprint("\n--- Reading data.txt with io.lines(filename) ---")for line in io.lines("data.txt") do print("io.lines Line: ", line)endWriting to Files
Section titled “Writing to Files”The file:write(...) method (or io.write(...) for default output) writes its arguments to the file. Arguments must be strings or numbers (which are converted to strings). It does not automatically add newlines or separators.
local file, err = io.open("output.txt", "w") -- Opens in write mode, overwrites if existsif file then file:write("Hello, Lua file output!\n") file:write("This is line 2.", " And this is part of line 2.\n") local num = 123 file:write("A number: ", num, "\n") print("Data written to output.txt") file:close()else print("Error writing to file: ", err)endOther File Operations
Section titled “Other File Operations”file:seek(whence, offset): Sets the file position.whencecan be"set"(from beginning),"cur"(from current position), or"end"(from end).offsetis a byte count.file:seek()returns the current position.file:seek("cur", 0)gets current position.file:flush(): Flushes any buffered writes to the file.io.type(obj): Returns"file"ifobjis an open file handle,"closed file"if it’s a closed file handle, ornilotherwise.io.tmpfile(): Returns a handle to a temporary file, opened in update mode ("w+b"). This file is automatically removed when the program exits or when the handle is closed.
Example with seek:
local file, err = io.open("data.txt", "r")if file then file:seek("set", 6) -- Seek to the 7th byte (0-indexed) local partial_read = file:read(5) -- Read 5 bytes print("\nRead after seek: '", partial_read, "'") -- Should be "Lua L"
local current_pos = file:seek("cur", 0) print("Current position: ", current_pos)
file:seek("end", -12) -- Seek 12 bytes from the end local end_data = file:read("*a") print("Reading last part: '", end_data, "'")
file:close()else print("Error in seek example: ", err)endError Handling: Always check the return values of I/O operations, especially io.open, file:read, and file:write, to handle potential errors gracefully.
Practical Application: File I/O is essential for reading configuration files, writing log files, processing data sets, and saving/loading application state.