文件操作 #

一、IO 库概述 #

1.1 IO 库类型 #

Lua 提供两种文件操作方式:

  • 简单模式:使用全局 IO 函数
  • 完全模式:使用文件句柄方法
lua
-- 简单模式
io.open("file.txt", "r")
io.read()
io.write("content")

-- 完全模式
local file = io.open("file.txt", "r")
file:read()
file:write("content")
file:close()

1.2 文件打开模式 #

模式 描述
r 只读(默认)
w 只写(覆盖)
a 追加
r+ 读写
w+ 读写(覆盖)
a+ 读写(追加)
b 二进制模式

二、简单 IO 操作 #

2.1 标准输入输出 #

lua
-- 标准输出
io.write("Hello, ")
io.write("World!\n")

-- 标准输入
io.write("请输入名字:")
local name = io.read()
print("你好," .. name)

-- 格式化输出
io.write(string.format("数字:%d\n", 42))

2.2 io.read 格式 #

lua
-- 读取一行
local line = io.read("*l")  -- 或 io.read()

-- 读取全部
local content = io.read("*a")

-- 读取数字
local num = io.read("*n")

-- 读取指定字符数
local chars = io.read(10)  -- 读取 10 个字符

2.3 临时文件 #

lua
-- 创建临时文件
local tmp = io.tmpfile()
tmp:write("临时内容")
tmp:seek("set", 0)
print(tmp:read("*a"))
-- 文件关闭时自动删除

三、完全文件操作 #

3.1 打开和关闭文件 #

lua
-- 打开文件
local file, err = io.open("data.txt", "r")
if not file then
    print("打开失败:" .. err)
    return
end

-- 使用文件
local content = file:read("*a")

-- 关闭文件
file:close()

-- 使用 pcall 确保关闭
local function read_file(path)
    local file = io.open(path, "r")
    if not file then return nil end
    
    local ok, result = pcall(function()
        return file:read("*a")
    end)
    
    file:close()
    return ok and result or nil
end

3.2 读取文件 #

lua
-- 读取整个文件
local file = io.open("data.txt", "r")
local content = file:read("*a")
file:close()

-- 逐行读取
local file = io.open("data.txt", "r")
for line in file:lines() do
    print(line)
end
file:close()

-- 读取指定字节数
local file = io.open("data.txt", "r")
local chunk = file:read(1024)  -- 读取 1KB
file:close()

3.3 写入文件 #

lua
-- 写入文件
local file = io.open("output.txt", "w")
file:write("Hello, World!\n")
file:write("第二行\n")
file:close()

-- 追加写入
local file = io.open("log.txt", "a")
file:write(os.date() .. ": 日志内容\n")
file:close()

-- 刷新缓冲区
file:flush()

3.4 文件定位 #

lua
local file = io.open("data.txt", "r")

-- 获取当前位置
local pos = file:seek()

-- 移动到开头
file:seek("set", 0)

-- 移动到末尾
local size = file:seek("end")

-- 相对移动
file:seek("cur", 10)  -- 向前移动 10 字节

file:close()

四、文件操作示例 #

4.1 复制文件 #

lua
local function copy_file(src, dst)
    local src_file = io.open(src, "rb")
    if not src_file then
        return nil, "无法打开源文件"
    end
    
    local dst_file = io.open(dst, "wb")
    if not dst_file then
        src_file:close()
        return nil, "无法创建目标文件"
    end
    
    while true do
        local chunk = src_file:read(4096)
        if not chunk then break end
        dst_file:write(chunk)
    end
    
    src_file:close()
    dst_file:close()
    return true
end

4.2 读取配置文件 #

lua
local function read_config(path)
    local config = {}
    local file = io.open(path, "r")
    
    if not file then
        return nil, "配置文件不存在"
    end
    
    for line in file:lines() do
        -- 跳过注释和空行
        if not line:match("^#") and not line:match("^%s*$") then
            local key, value = line:match("^%s*(%S+)%s*=%s*(.-)%s*$")
            if key and value then
                config[key] = value
            end
        end
    end
    
    file:close()
    return config
end

4.3 日志文件 #

lua
local Logger = {}
Logger.__index = Logger

function Logger.new(path)
    return setmetatable({
        file = io.open(path, "a")
    }, Logger)
end

function Logger:log(level, message)
    local timestamp = os.date("%Y-%m-%d %H:%M:%S")
    self.file:write(string.format("[%s] [%s] %s\n", timestamp, level, message))
    self.file:flush()
end

function Logger:info(message)
    self:log("INFO", message)
end

function Logger:error(message)
    self:log("ERROR", message)
end

function Logger:close()
    self.file:close()
end

-- 使用
local logger = Logger.new("app.log")
logger:info("应用启动")
logger:error("发生错误")
logger:close()

五、二进制文件 #

5.1 读写二进制文件 #

lua
-- 读取二进制文件
local function read_binary(path)
    local file = io.open(path, "rb")
    if not file then return nil end
    
    local content = file:read("*a")
    file:close()
    return content
end

-- 写入二进制文件
local function write_binary(path, data)
    local file = io.open(path, "wb")
    if not file then return nil end
    
    file:write(data)
    file:close()
    return true
end

5.2 二进制数据解析 #

lua
-- 读取二进制数据
local function read_uint32(file)
    local b1, b2, b3, b4 = file:read(4):byte(1, 4)
    return b1 + b2 * 256 + b3 * 65536 + b4 * 16777216
end

-- 写入二进制数据
local function write_uint32(file, n)
    file:write(string.char(
        n % 256,
        math.floor(n / 256) % 256,
        math.floor(n / 65536) % 256,
        math.floor(n / 16777216) % 256
    ))
end

六、目录操作 #

6.1 使用 lfs 库 #

bash
# 安装 luafilesystem
luarocks install luafilesystem
lua
local lfs = require("lfs")

-- 获取当前目录
print(lfs.currentdir())

-- 切换目录
lfs.chdir("/tmp")

-- 创建目录
lfs.mkdir("newdir")

-- 删除目录
lfs.rmdir("emptydir")

-- 获取文件信息
local attr = lfs.attributes("file.txt")
print(attr.mode)   -- 文件类型
print(attr.size)   -- 文件大小
print(attr.modification)  -- 修改时间

-- 遍历目录
for file in lfs.dir(".") do
    print(file)
end

6.2 递归遍历目录 #

lua
local lfs = require("lfs")

local function walk_dir(path, callback)
    for file in lfs.dir(path) do
        if file ~= "." and file ~= ".." then
            local fullpath = path .. "/" .. file
            local attr = lfs.attributes(fullpath)
            
            if attr.mode == "directory" then
                walk_dir(fullpath, callback)
            else
                callback(fullpath, attr)
            end
        end
    end
end

-- 使用
walk_dir(".", function(path, attr)
    print(path, attr.size)
end)

七、文件系统操作 #

7.1 文件存在检查 #

lua
local function file_exists(path)
    local file = io.open(path, "r")
    if file then
        file:close()
        return true
    end
    return false
end

7.2 获取文件大小 #

lua
local function get_file_size(path)
    local file = io.open(path, "rb")
    if not file then return nil end
    
    local size = file:seek("end")
    file:close()
    return size
end

7.3 文件重命名和删除 #

lua
-- 重命名
os.rename("old.txt", "new.txt")

-- 删除文件
os.remove("file.txt")

八、JSON 文件 #

8.1 读写 JSON #

lua
local json = require("dkjson")

-- 写入 JSON 文件
local function write_json(path, data)
    local file = io.open(path, "w")
    if not file then return nil end
    
    file:write(json.encode(data, {indent = true}))
    file:close()
    return true
end

-- 读取 JSON 文件
local function read_json(path)
    local file = io.open(path, "r")
    if not file then return nil end
    
    local content = file:read("*a")
    file:close()
    
    return json.decode(content)
end

-- 使用
local config = {
    name = "MyApp",
    version = "1.0",
    settings = {
        debug = true,
        port = 8080
    }
}

write_json("config.json", config)
local loaded = read_json("config.json")

九、CSV 文件 #

9.1 读写 CSV #

lua
-- 解析 CSV 行
local function parse_csv_line(line)
    local result = {}
    for field in line:gmatch('([^,]*)') do
        table.insert(result, field)
    end
    return result
end

-- 读取 CSV 文件
local function read_csv(path)
    local file = io.open(path, "r")
    if not file then return nil end
    
    local data = {}
    local headers = parse_csv_line(file:read())
    
    for line in file:lines() do
        local row = {}
        local values = parse_csv_line(line)
        for i, header in ipairs(headers) do
            row[header] = values[i]
        end
        table.insert(data, row)
    end
    
    file:close()
    return data
end

-- 写入 CSV 文件
local function write_csv(path, data, headers)
    local file = io.open(path, "w")
    if not file then return nil end
    
    file:write(table.concat(headers, ",") .. "\n")
    
    for _, row in ipairs(data) do
        local values = {}
        for _, header in ipairs(headers) do
            table.insert(values, row[header] or "")
        end
        file:write(table.concat(values, ",") .. "\n")
    end
    
    file:close()
    return true
end

十、总结 #

本章介绍了 Lua 文件操作:

  1. IO 库:简单模式和完全模式
  2. 文件读写:打开、读取、写入、关闭
  3. 文件定位:seek 操作
  4. 二进制文件:读写二进制数据
  5. 目录操作:使用 lfs 库
  6. 文件格式:JSON、CSV 文件处理

下一章,我们将学习元表与元方法。

最后更新:2026-03-27