Lua文件和IO操作
概述
文件和输入输出(I/O)操作是程序与外部世界交互的重要方式。Lua提供了完整的文件操作API,支持文本文件和二进制文件的读写,以及标准输入输出操作。
1. 文件操作基础
1.1 打开和关闭文件
lua
-- 基本文件打开
local file = io.open("test.txt", "r") -- 只读模式
if file then
print("文件打开成功")
file:close()
else
print("文件打开失败")
end
-- 文件打开模式
local modes = {
["r"] = "只读模式(默认)",
["w"] = "只写模式,清空文件内容",
["a"] = "追加模式,在文件末尾写入",
["r+"] = "读写模式,文件必须存在",
["w+"] = "读写模式,清空文件内容",
["a+"] = "读写模式,在文件末尾写入",
["rb"] = "二进制只读模式",
["wb"] = "二进制只写模式",
["ab"] = "二进制追加模式"
}
for mode, description in pairs(modes) do
print(mode .. ": " .. description)
end
-- 安全的文件打开
local function safe_open_file(filename, mode)
local file, err = io.open(filename, mode)
if not file then
error("无法打开文件 " .. filename .. ": " .. (err or "未知错误"))
end
return file
end
-- 使用示例
local success, file_or_error = pcall(safe_open_file, "example.txt", "w")
if success then
file_or_error:write("Hello, World!")
file_or_error:close()
print("文件写入成功")
else
print("错误:", file_or_error)
end1.2 文件读取操作
lua
-- 创建测试文件
local function create_test_file()
local file = io.open("test_data.txt", "w")
file:write("第一行内容\n")
file:write("第二行内容\n")
file:write("第三行内容\n")
file:write("123 456 789\n")
file:write("最后一行")
file:close()
end
create_test_file()
-- 不同的读取方式
local function demonstrate_read_methods()
local file = io.open("test_data.txt", "r")
if not file then return end
print("=== 读取方法演示 ===")
-- 1. 读取整个文件
file:seek("set", 0) -- 回到文件开头
local all_content = file:read("*a")
print("整个文件内容:")
print(all_content)
print("文件大小:", #all_content, "字节")
-- 2. 逐行读取
print("\n逐行读取:")
file:seek("set", 0) -- 回到文件开头
local line_number = 1
for line in file:lines() do
print(string.format("第%d行: %s", line_number, line))
line_number = line_number + 1
end
-- 3. 读取指定字节数
print("\n读取指定字节数:")
file:seek("set", 0) -- 回到文件开头
local chunk = file:read(10) -- 读取前10个字节
print("前10个字节:", chunk)
-- 4. 读取数字
file:seek("set", 0) -- 回到文件开头
-- 跳过前三行
file:read("*l")
file:read("*l")
file:read("*l")
local num1 = file:read("*n") -- 读取数字
local num2 = file:read("*n")
local num3 = file:read("*n")
print("读取的数字:", num1, num2, num3)
file:close()
end
demonstrate_read_methods()
-- 高级读取示例
local function advanced_file_reading()
local file = io.open("test_data.txt", "r")
if not file then return end
print("\n=== 高级读取示例 ===")
-- 读取文件的前N行
local function read_first_n_lines(file, n)
local lines = {}
file:seek("set", 0)
for i = 1, n do
local line = file:read("*l")
if not line then break end
lines[i] = line
end
return lines
end
local first_3_lines = read_first_n_lines(file, 3)
print("前3行:")
for i, line in ipairs(first_3_lines) do
print(" " .. i .. ": " .. line)
end
-- 读取文件的最后N行
local function read_last_n_lines(file, n)
local lines = {}
file:seek("set", 0)
-- 先读取所有行
for line in file:lines() do
table.insert(lines, line)
end
-- 返回最后n行
local start_index = math.max(1, #lines - n + 1)
local result = {}
for i = start_index, #lines do
table.insert(result, lines[i])
end
return result
end
local last_2_lines = read_last_n_lines(file, 2)
print("最后2行:")
for i, line in ipairs(last_2_lines) do
print(" " .. i .. ": " .. line)
end
file:close()
end
advanced_file_reading()1.3 文件写入操作
lua
-- 基本写入操作
local function basic_write_operations()
print("=== 基本写入操作 ===")
-- 1. 创建新文件并写入
local file = io.open("output.txt", "w")
file:write("Hello, Lua!\n")
file:write("这是第二行\n")
file:write(string.format("当前时间: %s\n", os.date()))
file:close()
print("创建文件 output.txt")
-- 2. 追加内容
file = io.open("output.txt", "a")
file:write("这是追加的内容\n")
file:write("追加的第二行\n")
file:close()
print("追加内容到 output.txt")
-- 3. 格式化写入
file = io.open("formatted_output.txt", "w")
local data = {
{name = "Alice", age = 30, score = 95.5},
{name = "Bob", age = 25, score = 87.2},
{name = "Charlie", age = 35, score = 92.8}
}
file:write("姓名\t\t年龄\t分数\n")
file:write(string.rep("-", 30) .. "\n")
for _, person in ipairs(data) do
file:write(string.format("%-10s\t%d\t%.1f\n",
person.name, person.age, person.score))
end
file:close()
print("创建格式化文件 formatted_output.txt")
end
basic_write_operations()
-- 安全写入函数
local function safe_write_file(filename, content, mode)
mode = mode or "w"
local file, err = io.open(filename, mode)
if not file then
return false, "无法打开文件: " .. (err or "未知错误")
end
local success, write_err = pcall(function()
file:write(content)
end)
file:close()
if success then
return true, nil
else
return false, "写入失败: " .. write_err
end
end
-- 批量写入
local function batch_write_example()
print("\n=== 批量写入示例 ===")
local lines = {}
for i = 1, 1000 do
lines[i] = string.format("这是第 %d 行数据", i)
end
local content = table.concat(lines, "\n")
local success, err = safe_write_file("large_file.txt", content)
if success then
print("成功写入1000行数据")
else
print("写入失败:", err)
end
end
batch_write_example()2. 文件位置操作
2.1 文件指针操作
lua
-- 文件指针操作示例
local function file_pointer_operations()
print("=== 文件指针操作 ===")
-- 创建测试文件
local file = io.open("pointer_test.txt", "w")
file:write("0123456789ABCDEFGHIJ")
file:close()
-- 重新打开进行读取
file = io.open("pointer_test.txt", "r")
-- 获取当前位置
local pos = file:seek()
print("初始位置:", pos) -- 0
-- 读取5个字符
local data = file:read(5)
print("读取的数据:", data) -- 01234
-- 获取当前位置
pos = file:seek()
print("读取后位置:", pos) -- 5
-- 移动到文件开头
file:seek("set", 0)
pos = file:seek()
print("移动到开头后位置:", pos) -- 0
-- 移动到文件末尾
file:seek("end", 0)
pos = file:seek()
print("移动到末尾后位置:", pos) -- 20
-- 相对移动
file:seek("cur", -5) -- 向前移动5个位置
pos = file:seek()
print("相对移动后位置:", pos) -- 15
-- 读取当前位置的数据
data = file:read(3)
print("当前位置读取:", data) -- FGH
file:close()
end
file_pointer_operations()
-- 随机访问文件
local function random_access_example()
print("\n=== 随机访问示例 ===")
-- 创建索引文件
local records = {
{id = 1, name = "Alice", data = "数据1"},
{id = 2, name = "Bob", data = "数据2"},
{id = 3, name = "Charlie", data = "数据3"}
}
local file = io.open("records.txt", "w")
local index = {} -- 记录每条记录的位置
for _, record in ipairs(records) do
local pos = file:seek() -- 记录当前位置
local line = string.format("%d|%s|%s\n", record.id, record.name, record.data)
file:write(line)
index[record.id] = {position = pos, length = #line}
end
file:close()
-- 随机读取记录
file = io.open("records.txt", "r")
local function read_record_by_id(id)
local record_info = index[id]
if not record_info then
return nil, "记录不存在"
end
file:seek("set", record_info.position)
local line = file:read("*l")
-- 解析记录
local parts = {}
for part in string.gmatch(line, "([^|]+)") do
table.insert(parts, part)
end
return {
id = tonumber(parts[1]),
name = parts[2],
data = parts[3]
}
end
-- 测试随机访问
for _, id in ipairs({3, 1, 2}) do
local record = read_record_by_id(id)
if record then
print(string.format("ID %d: %s - %s", record.id, record.name, record.data))
end
end
file:close()
end
random_access_example()3. 二进制文件操作
3.1 二进制读写
lua
-- 二进制文件操作
local function binary_file_operations()
print("=== 二进制文件操作 ===")
-- 写入二进制数据
local function write_binary_data()
local file = io.open("binary_data.bin", "wb")
-- 写入不同类型的数据
local data = {
0x12, 0x34, 0x56, 0x78, -- 字节
0x1234, -- 16位整数
0x12345678, -- 32位整数
}
for _, value in ipairs(data) do
-- 将数字转换为字节写入
if value <= 0xFF then
file:write(string.char(value))
elseif value <= 0xFFFF then
-- 小端序写入16位整数
file:write(string.char(value & 0xFF))
file:write(string.char((value >> 8) & 0xFF))
else
-- 小端序写入32位整数
file:write(string.char(value & 0xFF))
file:write(string.char((value >> 8) & 0xFF))
file:write(string.char((value >> 16) & 0xFF))
file:write(string.char((value >> 24) & 0xFF))
end
end
file:close()
print("二进制数据写入完成")
end
-- 读取二进制数据
local function read_binary_data()
local file = io.open("binary_data.bin", "rb")
if not file then
print("无法打开二进制文件")
return
end
print("读取二进制数据:")
-- 读取单个字节
for i = 1, 4 do
local byte = file:read(1)
if byte then
print(string.format("字节 %d: 0x%02X", i, string.byte(byte)))
end
end
-- 读取16位整数(小端序)
local low = string.byte(file:read(1))
local high = string.byte(file:read(1))
local int16 = low + (high << 8)
print(string.format("16位整数: 0x%04X", int16))
-- 读取32位整数(小端序)
local bytes = {}
for i = 1, 4 do
bytes[i] = string.byte(file:read(1))
end
local int32 = bytes[1] + (bytes[2] << 8) + (bytes[3] << 16) + (bytes[4] << 24)
print(string.format("32位整数: 0x%08X", int32))
file:close()
end
write_binary_data()
read_binary_data()
end
binary_file_operations()
-- 二进制文件工具函数
local BinaryFile = {}
BinaryFile.__index = BinaryFile
function BinaryFile.new(filename, mode)
local file = io.open(filename, mode)
if not file then
error("无法打开文件: " .. filename)
end
return setmetatable({
file = file,
filename = filename
}, BinaryFile)
end
function BinaryFile:write_uint8(value)
self.file:write(string.char(value & 0xFF))
end
function BinaryFile:write_uint16_le(value)
self.file:write(string.char(value & 0xFF))
self.file:write(string.char((value >> 8) & 0xFF))
end
function BinaryFile:write_uint32_le(value)
self.file:write(string.char(value & 0xFF))
self.file:write(string.char((value >> 8) & 0xFF))
self.file:write(string.char((value >> 16) & 0xFF))
self.file:write(string.char((value >> 24) & 0xFF))
end
function BinaryFile:read_uint8()
local byte = self.file:read(1)
return byte and string.byte(byte) or nil
end
function BinaryFile:read_uint16_le()
local low = self:read_uint8()
local high = self:read_uint8()
if low and high then
return low + (high << 8)
end
return nil
end
function BinaryFile:read_uint32_le()
local bytes = {}
for i = 1, 4 do
bytes[i] = self:read_uint8()
if not bytes[i] then return nil end
end
return bytes[1] + (bytes[2] << 8) + (bytes[3] << 16) + (bytes[4] << 24)
end
function BinaryFile:close()
self.file:close()
end
-- 使用二进制文件工具
local function test_binary_tools()
print("\n=== 二进制工具测试 ===")
-- 写入数据
local writer = BinaryFile.new("test_binary.bin", "wb")
writer:write_uint8(0x12)
writer:write_uint16_le(0x3456)
writer:write_uint32_le(0x789ABCDE)
writer:close()
-- 读取数据
local reader = BinaryFile.new("test_binary.bin", "rb")
local uint8 = reader:read_uint8()
local uint16 = reader:read_uint16_le()
local uint32 = reader:read_uint32_le()
reader:close()
print(string.format("读取结果: 0x%02X, 0x%04X, 0x%08X", uint8, uint16, uint32))
end
test_binary_tools()4. 标准输入输出
4.1 标准IO操作
lua
-- 标准输入输出操作
local function standard_io_operations()
print("=== 标准IO操作 ===")
-- 标准输出
io.write("这是使用io.write输出的文本\n")
io.stdout:write("这是直接使用stdout输出的文本\n")
-- 格式化输出
io.write(string.format("格式化输出: %s, %d, %.2f\n", "测试", 42, 3.14159))
-- 刷新输出缓冲区
io.write("输出但不换行")
io.flush() -- 强制刷新
io.write(" - 继续输出\n")
-- 标准错误输出
io.stderr:write("这是错误信息\n")
end
standard_io_operations()
-- 模拟交互式输入(实际使用时取消注释)
local function interactive_input_demo()
print("\n=== 交互式输入演示 ===")
--[[
-- 读取一行输入
io.write("请输入您的姓名: ")
local name = io.read("*l")
print("您好, " .. name .. "!")
-- 读取数字
io.write("请输入一个数字: ")
local number = io.read("*n")
if number then
print("您输入的数字是: " .. number)
print("它的平方是: " .. (number * number))
else
print("输入的不是有效数字")
end
-- 读取多个值
io.write("请输入两个数字(用空格分隔): ")
local a, b = io.read("*n", "*n")
if a and b then
print(string.format("%g + %g = %g", a, b, a + b))
end
--]]
print("(交互式输入演示代码已注释,实际使用时请取消注释)")
end
interactive_input_demo()
-- 输入验证函数
local function get_valid_input(prompt, validator, error_message)
while true do
io.write(prompt)
local input = io.read("*l")
if validator(input) then
return input
else
print(error_message or "输入无效,请重试")
end
end
end
-- 输入验证示例
local function input_validation_example()
print("\n=== 输入验证示例 ===")
-- 验证器函数
local function is_valid_email(email)
return string.match(email, "^[%w%.%-_]+@[%w%.%-_]+%.%w+$") ~= nil
end
local function is_valid_age(age_str)
local age = tonumber(age_str)
return age and age >= 0 and age <= 150
end
--[[
-- 获取有效的邮箱地址
local email = get_valid_input(
"请输入邮箱地址: ",
is_valid_email,
"邮箱格式不正确,请重新输入"
)
-- 获取有效的年龄
local age_str = get_valid_input(
"请输入年龄 (0-150): ",
is_valid_age,
"年龄必须是0-150之间的数字"
)
print("验证通过!")
print("邮箱: " .. email)
print("年龄: " .. age_str)
--]]
print("(输入验证示例代码已注释,实际使用时请取消注释)")
end
input_validation_example()5. 文件系统操作
5.1 文件和目录信息
lua
-- 文件系统操作
local function file_system_operations()
print("=== 文件系统操作 ===")
-- 检查文件是否存在
local function file_exists(filename)
local file = io.open(filename, "r")
if file then
file:close()
return true
end
return false
end
-- 获取文件大小
local function get_file_size(filename)
local file = io.open(filename, "r")
if not file then return nil end
local size = file:seek("end")
file:close()
return size
end
-- 测试文件操作
local test_files = {"test_data.txt", "output.txt", "nonexistent.txt"}
for _, filename in ipairs(test_files) do
if file_exists(filename) then
local size = get_file_size(filename)
print(string.format("%s: 存在, 大小 %d 字节", filename, size))
else
print(string.format("%s: 不存在", filename))
end
end
-- 文件复制
local function copy_file(source, destination)
local src_file = io.open(source, "rb")
if not src_file then
return false, "无法打开源文件"
end
local dst_file = io.open(destination, "wb")
if not dst_file then
src_file:close()
return false, "无法创建目标文件"
end
-- 分块复制
local chunk_size = 4096
while true do
local chunk = src_file:read(chunk_size)
if not chunk then break end
dst_file:write(chunk)
end
src_file:close()
dst_file:close()
return true
end
-- 测试文件复制
if file_exists("test_data.txt") then
local success, err = copy_file("test_data.txt", "test_data_copy.txt")
if success then
print("文件复制成功: test_data.txt -> test_data_copy.txt")
else
print("文件复制失败:", err)
end
end
end
file_system_operations()
-- 目录操作(需要lfs库或使用os.execute)
local function directory_operations()
print("\n=== 目录操作 ===")
-- 创建目录
local function create_directory(dirname)
local success = os.execute("mkdir " .. dirname)
return success == 0 or success == true
end
-- 删除文件
local function delete_file(filename)
return os.remove(filename)
end
-- 列出目录内容(Windows)
local function list_directory_windows(dirname)
local handle = io.popen("dir \"" .. dirname .. "\" /b")
if not handle then return {} end
local files = {}
for line in handle:lines() do
table.insert(files, line)
end
handle:close()
return files
end
-- 列出目录内容(Unix/Linux)
local function list_directory_unix(dirname)
local handle = io.popen("ls \"" .. dirname .. "\"")
if not handle then return {} end
local files = {}
for line in handle:lines() do
table.insert(files, line)
end
handle:close()
return files
end
-- 跨平台目录列表
local function list_directory(dirname)
if package.config:sub(1,1) == "\\" then
return list_directory_windows(dirname)
else
return list_directory_unix(dirname)
end
end
-- 测试目录操作
print("当前目录内容:")
local files = list_directory(".")
for i, file in ipairs(files) do
if i <= 10 then -- 只显示前10个
print(" " .. file)
elseif i == 11 then
print(" ...")
break
end
end
end
directory_operations()6. 高级文件操作
6.1 文件监控和处理
lua
-- 高级文件操作
local FileProcessor = {}
FileProcessor.__index = FileProcessor
function FileProcessor.new()
return setmetatable({
processors = {},
filters = {}
}, FileProcessor)
end
function FileProcessor:add_processor(name, processor_func)
self.processors[name] = processor_func
end
function FileProcessor:add_filter(filter_func)
table.insert(self.filters, filter_func)
end
function FileProcessor:process_file(filename)
-- 检查文件是否通过所有过滤器
for _, filter in ipairs(self.filters) do
if not filter(filename) then
return false, "文件被过滤器拒绝"
end
end
local results = {}
-- 应用所有处理器
for name, processor in pairs(self.processors) do
local success, result = pcall(processor, filename)
if success then
results[name] = result
else
results[name] = "处理失败: " .. result
end
end
return true, results
end
-- 使用文件处理器
local function file_processor_example()
print("\n=== 文件处理器示例 ===")
local processor = FileProcessor.new()
-- 添加过滤器
processor:add_filter(function(filename)
return string.match(filename, "%.txt$") ~= nil -- 只处理.txt文件
end)
-- 添加处理器
processor:add_processor("line_count", function(filename)
local file = io.open(filename, "r")
if not file then return "无法打开文件" end
local count = 0
for _ in file:lines() do
count = count + 1
end
file:close()
return count .. " 行"
end)
processor:add_processor("word_count", function(filename)
local file = io.open(filename, "r")
if not file then return "无法打开文件" end
local content = file:read("*a")
file:close()
local word_count = 0
for word in string.gmatch(content, "%S+") do
word_count = word_count + 1
end
return word_count .. " 个单词"
end)
processor:add_processor("file_size", function(filename)
local file = io.open(filename, "r")
if not file then return "无法打开文件" end
local size = file:seek("end")
file:close()
return size .. " 字节"
end)
-- 处理文件
local test_files = {"test_data.txt", "output.txt", "binary_data.bin"}
for _, filename in ipairs(test_files) do
local success, results = processor:process_file(filename)
if success then
print(filename .. ":")
for processor_name, result in pairs(results) do
print(" " .. processor_name .. ": " .. result)
end
else
print(filename .. ": " .. results)
end
end
end
file_processor_example()
-- 文件批处理
local function batch_file_processing()
print("\n=== 批处理示例 ===")
-- 批量创建测试文件
local function create_test_files()
local file_contents = {
"这是第一个测试文件\n包含两行内容",
"第二个文件\n有三行\n内容",
"第三个文件只有一行",
"最后一个文件\n有四行\n不同的\n内容"
}
for i, content in ipairs(file_contents) do
local filename = string.format("batch_test_%d.txt", i)
local file = io.open(filename, "w")
file:write(content)
file:close()
end
print("创建了4个测试文件")
end
-- 批量处理文件
local function process_batch_files()
local total_lines = 0
local total_size = 0
local file_count = 0
for i = 1, 4 do
local filename = string.format("batch_test_%d.txt", i)
local file = io.open(filename, "r")
if file then
-- 统计行数
local lines = 0
for _ in file:lines() do
lines = lines + 1
end
-- 获取文件大小
local size = file:seek("end")
file:close()
total_lines = total_lines + lines
total_size = total_size + size
file_count = file_count + 1
print(string.format("%s: %d 行, %d 字节", filename, lines, size))
end
end
print(string.format("总计: %d 个文件, %d 行, %d 字节",
file_count, total_lines, total_size))
end
create_test_files()
process_batch_files()
-- 清理测试文件
for i = 1, 4 do
local filename = string.format("batch_test_%d.txt", i)
os.remove(filename)
end
print("清理测试文件完成")
end
batch_file_processing()7. 性能优化和最佳实践
7.1 高效文件操作
lua
-- 性能优化示例
local function performance_optimization()
print("=== 性能优化示例 ===")
-- 创建大文件用于测试
local function create_large_file(filename, lines)
local file = io.open(filename, "w")
for i = 1, lines do
file:write(string.format("这是第 %d 行数据,包含一些测试内容\n", i))
end
file:close()
end
create_large_file("large_test.txt", 10000)
-- 低效的逐行处理
local function slow_line_processing(filename)
local start_time = os.clock()
local file = io.open(filename, "r")
local line_count = 0
for line in file:lines() do
line_count = line_count + 1
-- 模拟处理每一行
string.upper(line)
end
file:close()
local end_time = os.clock()
return line_count, end_time - start_time
end
-- 高效的块处理
local function fast_chunk_processing(filename)
local start_time = os.clock()
local file = io.open(filename, "r")
local line_count = 0
local chunk_size = 8192
while true do
local chunk = file:read(chunk_size)
if not chunk then break end
-- 统计换行符数量
for _ in string.gmatch(chunk, "\n") do
line_count = line_count + 1
end
end
file:close()
local end_time = os.clock()
return line_count, end_time - start_time
end
-- 性能比较
local slow_lines, slow_time = slow_line_processing("large_test.txt")
local fast_lines, fast_time = fast_chunk_processing("large_test.txt")
print(string.format("逐行处理: %d 行, %.4f 秒", slow_lines, slow_time))
print(string.format("块处理: %d 行, %.4f 秒", fast_lines, fast_time))
print(string.format("性能提升: %.2f 倍", slow_time / fast_time))
-- 清理
os.remove("large_test.txt")
end
performance_optimization()
-- 内存友好的大文件处理
local function memory_efficient_processing()
print("\n=== 内存友好处理 ===")
-- 创建超大文件
local function create_huge_file(filename, size_mb)
local file = io.open(filename, "w")
local line = string.rep("a", 80) .. "\n" -- 81字节的行
local lines_per_mb = math.floor(1024 * 1024 / 81)
for mb = 1, size_mb do
for line_in_mb = 1, lines_per_mb do
file:write(line)
end
end
file:close()
end
-- 流式处理大文件
local function stream_process_file(input_filename, output_filename, processor)
local input_file = io.open(input_filename, "r")
local output_file = io.open(output_filename, "w")
if not input_file or not output_file then
if input_file then input_file:close() end
if output_file then output_file:close() end
return false, "无法打开文件"
end
local chunk_size = 4096
local processed_bytes = 0
while true do
local chunk = input_file:read(chunk_size)
if not chunk then break end
local processed_chunk = processor(chunk)
output_file:write(processed_chunk)
processed_bytes = processed_bytes + #chunk
-- 定期报告进度
if processed_bytes % (1024 * 1024) == 0 then
print(string.format("已处理 %d MB", processed_bytes / (1024 * 1024)))
end
end
input_file:close()
output_file:close()
return true, processed_bytes
end
-- 示例:将文件内容转换为大写
local function uppercase_processor(chunk)
return string.upper(chunk)
end
print("创建测试文件...")
create_huge_file("huge_test.txt", 5) -- 5MB文件
print("开始流式处理...")
local success, bytes = stream_process_file("huge_test.txt", "huge_upper.txt", uppercase_processor)
if success then
print(string.format("处理完成,共处理 %d 字节", bytes))
else
print("处理失败:", bytes)
end
-- 清理
os.remove("huge_test.txt")
os.remove("huge_upper.txt")
end
memory_efficient_processing()7.2 错误处理和资源管理
lua
-- 安全的文件操作模式
local function safe_file_operations()
print("\n=== 安全文件操作 ===")
-- RAII风格的文件操作
local function with_file(filename, mode, operation)
local file, err = io.open(filename, mode)
if not file then
return nil, "无法打开文件: " .. (err or "未知错误")
end
local success, result = pcall(operation, file)
file:close()
if success then
return result
else
return nil, "操作失败: " .. result
end
end
-- 使用RAII模式
local result, err = with_file("test_data.txt", "r", function(file)
local lines = {}
for line in file:lines() do
table.insert(lines, line)
end
return lines
end)
if result then
print("成功读取", #result, "行")
else
print("读取失败:", err)
end
-- 事务性文件操作
local function atomic_file_write(filename, content)
local temp_filename = filename .. ".tmp"
-- 写入临时文件
local success, err = with_file(temp_filename, "w", function(file)
file:write(content)
return true
end)
if not success then
os.remove(temp_filename)
return false, err
end
-- 原子性重命名(在大多数系统上)
local rename_success = os.rename(temp_filename, filename)
if not rename_success then
os.remove(temp_filename)
return false, "无法重命名临时文件"
end
return true
end
-- 测试原子写入
local content = "这是原子写入的内容\n包含多行数据\n"
local success, err = atomic_file_write("atomic_test.txt", content)
if success then
print("原子写入成功")
else
print("原子写入失败:", err)
end
-- 清理
os.remove("atomic_test.txt")
end
safe_file_operations()8. 实际应用示例
8.1 日志文件处理
lua
-- 日志文件处理系统
local LogProcessor = {}
LogProcessor.__index = LogProcessor
function LogProcessor.new()
return setmetatable({
patterns = {},
statistics = {}
}, LogProcessor)
end
function LogProcessor:add_pattern(name, pattern, extractor)
self.patterns[name] = {
pattern = pattern,
extractor = extractor or function(match) return match end
}
end
function LogProcessor:process_log_file(filename)
local file = io.open(filename, "r")
if not file then
return false, "无法打开日志文件"
end
local line_number = 0
local matches = {}
for line in file:lines() do
line_number = line_number + 1
for pattern_name, pattern_info in pairs(self.patterns) do
local match = string.match(line, pattern_info.pattern)
if match then
if not matches[pattern_name] then
matches[pattern_name] = {}
end
table.insert(matches[pattern_name], {
line_number = line_number,
data = pattern_info.extractor(match),
original_line = line
})
end
end
end
file:close()
return true, matches
end
-- 使用日志处理器
local function log_processing_example()
print("\n=== 日志处理示例 ===")
-- 创建示例日志文件
local log_content = [[
2023-12-25 10:00:01 INFO User login: alice@example.com
2023-12-25 10:00:15 ERROR Database connection failed
2023-12-25 10:00:30 INFO User login: bob@example.com
2023-12-25 10:01:00 WARN High memory usage: 85%
2023-12-25 10:01:15 ERROR File not found: /path/to/file.txt
2023-12-25 10:01:30 INFO User logout: alice@example.com
]]
local file = io.open("sample.log", "w")
file:write(log_content)
file:close()
-- 配置日志处理器
local processor = LogProcessor.new()
processor:add_pattern("errors", "ERROR (.+)", function(error_msg)
return {type = "error", message = error_msg}
end)
processor:add_pattern("user_actions", "User (%w+): ([%w@%.]+)", function(action, user)
return {action = action, user = user}
end)
processor:add_pattern("warnings", "WARN (.+)", function(warning_msg)
return {type = "warning", message = warning_msg}
end)
-- 处理日志
local success, results = processor:process_log_file("sample.log")
if success then
print("日志分析结果:")
for pattern_name, matches in pairs(results) do
print(string.format("\n%s (%d 条):", pattern_name, #matches))
for _, match in ipairs(matches) do
print(string.format(" 行 %d: %s", match.line_number,
type(match.data) == "table" and
table.concat({match.data.action or match.data.type,
match.data.user or match.data.message}, " - ") or
tostring(match.data)))
end
end
else
print("日志处理失败:", results)
end
-- 清理
os.remove("sample.log")
end
log_processing_example()8.2 配置文件管理
lua
-- 配置文件管理器
local ConfigManager = {}
ConfigManager.__index = ConfigManager
function ConfigManager.new(filename)
return setmetatable({
filename = filename,
config = {},
comments = {}
}, ConfigManager)
end
function ConfigManager:load()
local file = io.open(self.filename, "r")
if not file then
return false, "配置文件不存在"
end
local line_number = 0
local current_section = nil
for line in file:lines() do
line_number = line_number + 1
-- 去除前后空白
line = string.match(line, "^%s*(.-)%s*$")
-- 跳过空行
if line == "" then
goto continue
end
-- 处理注释
if string.match(line, "^#") then
self.comments[line_number] = line
goto continue
end
-- 处理节标题
local section = string.match(line, "^%[(.+)%]$")
if section then
current_section = section
if not self.config[section] then
self.config[section] = {}
end
goto continue
end
-- 处理键值对
local key, value = string.match(line, "^([^=]+)=(.*)$")
if key and value then
key = string.match(key, "^%s*(.-)%s*$")
value = string.match(value, "^%s*(.-)%s*$")
if current_section then
self.config[current_section][key] = value
else
self.config[key] = value
end
end
::continue::
end
file:close()
return true
end
function ConfigManager:save()
local file = io.open(self.filename, "w")
if not file then
return false, "无法写入配置文件"
end
-- 写入全局配置
for key, value in pairs(self.config) do
if type(value) ~= "table" then
file:write(string.format("%s=%s\n", key, value))
end
end
-- 写入节配置
for section, section_config in pairs(self.config) do
if type(section_config) == "table" then
file:write(string.format("\n[%s]\n", section))
for key, value in pairs(section_config) do
file:write(string.format("%s=%s\n", key, value))
end
end
end
file:close()
return true
end
function ConfigManager:get(section, key)
if key then
return self.config[section] and self.config[section][key]
else
return self.config[section]
end
end
function ConfigManager:set(section, key, value)
if value then
if not self.config[section] then
self.config[section] = {}
end
self.config[section][key] = value
else
self.config[section] = key
end
end
-- 使用配置管理器
local function config_manager_example()
print("\n=== 配置管理示例 ===")
-- 创建示例配置文件
local config_content = [[
# 应用程序配置文件
app_name=MyApp
version=1.0.0
[database]
host=localhost
port=3306
username=admin
password=secret
[server]
port=8080
debug=true
]]
local file = io.open("app.conf", "w")
file:write(config_content)
file:close()
-- 加载配置
local config = ConfigManager.new("app.conf")
local success, err = config:load()
if success then
print("配置加载成功")
-- 读取配置
print("应用名称:", config:get("app_name"))
print("数据库主机:", config:get("database", "host"))
print("服务器端口:", config:get("server", "port"))
-- 修改配置
config:set("server", "port", "9090")
config:set("server", "ssl", "true")
-- 保存配置
local save_success = config:save()
if save_success then
print("配置保存成功")
else
print("配置保存失败")
end
else
print("配置加载失败:", err)
end
-- 清理
os.remove("app.conf")
end
config_manager_example()总结
Lua的文件和IO操作提供了完整的功能:
- 基本文件操作 - 打开、读取、写入、关闭文件
- 文件位置控制 - 支持随机访问和文件指针操作
- 二进制文件支持 - 处理二进制数据
- 标准IO - 与标准输入输出交互
- 文件系统操作 - 文件存在性检查、复制等
- 性能优化 - 块读取、流式处理等高效方法
- 错误处理 - 完善的错误处理和资源管理
- 实际应用 - 日志处理、配置管理等实用示例
掌握这些文件操作技术可以让你的Lua程序能够有效地处理各种文件和数据操作任务。