0Pricing
Lua Academy · Lesson

Writing and Appending to Files

Write strings to files and append data without overwriting.

Writing and Appending to Files is a free Lua Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Lua Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

f:write() Basics

f:write(...) writes one or more strings (or numbers) to the file. It does not add newlines automatically. Returns the file handle on success (enabling chaining), or nil, errMessage, errCode on failure.

local f = io.open("output.txt", "w")
if f then
  f:write("Hello, ")
  f:write("World")
  f:write("!\n")
  f:write("Line 2\n")
  f:close()
end

Writing Multiple Values

f:write() accepts multiple arguments and writes them all sequentially. Values must be strings or numbers — passing other types raises an error. Use tostring() to convert booleans, tables, etc.

local f = io.open("log.txt", "w")
f:write("Name: ", "Alice", "\n")
f:write("Age: ", 30, "\n")
f:write("Score: ", string.format("%.1f", 95.5), "\n")
f:close()

Formatted Writing

Combine string.format with f:write for precise output. This pattern is common for generating reports, log files, and data exports with specific formatting requirements.

local data = {
  {name="Alice", score=95, grade="A"},
  {name="Bob",   score=87, grade="B"},
}

local f = io.open("report.txt", "w")
f:write(string.format("%-12s  %5s  %s\n","Name","Score","Grade"))
f:write(string.rep("-",25) .. "\n")
for _, r in ipairs(data) do
  f:write(string.format("%-12s  %5d  %s\n",r.name,r.score,r.grade))
end
f:close()

Append Mode

Mode "a" always writes at the end of the file. The file position for reads is at the start, but writes always go to the end. Use for logs, audit trails, and any file where you want to add without erasing.

local function appendLog(msg)
  local f = io.open("app.log", "a")
  if f then
    local ts = os.date("%Y-%m-%d %H:%M:%S")
    f:write(string.format("[%s] %s\n", ts, msg))
    f:close()
  end
end

appendLog("Server started")
appendLog("User logged in: Alice")
appendLog("Request processed")

f:flush() and Buffering

File I/O in Lua is buffered. Data written with f:write() may sit in a buffer before reaching disk. f:flush() forces the buffer to disk without closing the file. Always flush before you need another process to see the data.

local f = io.open("stream.txt", "w")
for i = 1, 5 do
  f:write("Line " .. i .. "\n")
  f:flush()   -- ensure each line is on disk
  -- simulate work
end
f:close()

Writing Binary Data

In binary write mode ("wb"), write raw bytes with string.char(). This is how you create binary file formats, images, or protocol messages. Use string.pack (Lua 5.3+) for structured binary data.

local f = io.open("bytes.bin", "wb")
if f then
  -- Write raw bytes
  f:write(string.char(0xFF, 0x00, 0xAB, 0xCD))
  -- Write a 4-byte little-endian integer (Lua 5.3+)
  f:write(string.pack("<I4", 12345))
  f:close()
  print("Written binary file")
end

io.write vs f:write

io.write() writes to the current default output (initially stdout). f:write() writes to a specific file handle. Unlike print(), neither adds a newline or tab separators, giving you full control over output formatting.

-- io.write to stdout
io.write("Enter name: ")
-- (would read input here)

-- f:write to file
local f = io.open("out.txt", "w")
f:write("No auto newline")
f:write(" appended directly")
f:write("\n")  -- explicit newline
f:close()

-- print adds tabs and newline automatically
print("a", "b", "c")   -- a  b  c (tab-separated)

Atomic Write Pattern

For safety, write to a temporary file then rename it. This avoids a window where the output file is partially written. If the process crashes mid-write, the original file is untouched.

local function atomicWrite(path, content)
  local tmp = path .. ".tmp"
  local f, err = io.open(tmp, "w")
  if not f then return nil, err end
  f:write(content)
  f:close()
  -- os.rename is atomic on most filesystems
  local ok, err2 = os.rename(tmp, path)
  if not ok then
    os.remove(tmp)
    return nil, err2
  end
  return true
end

Writing Tables as CSV

Serialize a table of records to CSV format: write a header row, then one row per record, converting all values to strings and joining with commas.

local function writeCSV(path, headers, rows)
  local f = io.open(path, "w")
  if not f then return end
  f:write(table.concat(headers, ",") .. "\n")
  for _, row in ipairs(rows) do
    local fields = {}
    for _, h in ipairs(headers) do
      fields[#fields+1] = tostring(row[h] or "")
    end
    f:write(table.concat(fields, ",") .. "\n")
  end
  f:close()
end

writeCSV("data.csv",
  {"name","age","score"},
  {{name="Alice",age=30,score=95},{name="Bob",age=25,score=87}}
)

f:write Return Value

f:write() returns the file handle on success, enabling method chaining. On failure it returns nil, an error message, and an error code. Always check for errors in production code, especially for write operations on storage-limited systems.

local f = io.open("out.txt", "w")

-- Chaining writes
local ok, err = f:write("line1\n"):write("line2\n"):write("line3\n")
if not ok then
  print("Write failed:", err)
else
  print("All writes succeeded")
end
f:close()

Quick Check

What is the difference between "w" and "a" modes in io.open?

Recap: Writing Files

Summary:

  • f:write(...) — write strings/numbers; no auto newline
  • "w" truncates, "a" appends
  • f:flush() forces buffer to disk
  • io.write() writes to default output (stdout)
  • Atomic write: write to tmp, then rename
  • Check write return values in production

Frequently asked questions

Is the “Writing and Appending to Files” lesson free?

Yes — the full text of “Writing and Appending to Files” is free to read here on the web, and the Lua Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Lua Academy course, upgrade to CoddyKit PRO.

What will I learn in “Writing and Appending to Files”?

Write strings to files and append data without overwriting. You practise Lua Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Lua Academy?

No prior experience is required. Lua Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Writing and Appending to Files” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Lua Academy lesson?

Yes. Every Lua Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Opening Files with io.open
  2. Reading File Contents
  3. Writing and Appending to Files
  4. Closing Files and Error Handling
← Back to Lua Academy