主题
📁 文件操作库 - 简单易懂的文件处理指南
📖 什么是文件操作?
文件操作就像使用记事本一样,可以打开文件、读取内容、写入内容、保存文件。程序可以通过文件来保存数据、读取配置、记录日志等。
能做什么:
- 📖 读取文件(比如读取配置文件)
- ✏️ 写入文件(比如保存数据到文件)
- 📝 追加内容(比如往日志文件添加新记录)
- 📂 检查文件是否存在
- 📄 获取文件信息
实际应用:
- 读取设备配置文件
- 保存采集到的数据
- 记录运行日志
- 导出报表文件
- 备份重要数据
🚀 3分钟快速上手
示例1: 文本文件操作(写入,读取,删除操作)
lua
local file_path = "/spiffs/example.txt"-- 文件路径(可替换为实际路径)WIFI版PLC文件名必须“/spiffs/”开头,wifi版只有这一个目录可用,如果不存在目录将失败
-- 写入文件示例
local function write_file()
local file = io.open(file_path, "w")-- 以写入模式打开文件(若文件存在则覆盖)
if not file then
print("无法打开文件进行写入")
return
end
-- 写入多行内容
file:write("这是第一行文本\n")
file:write("第二行包含数字: ", 123, "\n")
file:write("第三行使用格式化: %s - %d\n", "Lua", 5.3)
file:close()-- 关闭文件句柄
print("文件写入完成")
end
-- 读取文件示例
local function read_file()
local file = io.open(file_path, "r")-- 以读取模式打开文件
if not file then
print("无法打开文件进行读取")
return
end
-- 逐行读取并打印
print("\n文件内容:")
for line in file:lines() do
print(line)
end
file:close()-- 关闭文件
end
-- 执行写入和读取操作
write_file()
read_file()
-- 追加写入示例
local function append_file()
local file = io.open(file_path, "a") -- 追加模式
if file then
file:write("\n这是追加的内容\n")
file:close()
end
end
append_file()
print("\n追加后再次读取:")
read_file()
-- 删除文件函数(带错误处理)
local function delete_file()
-- 检查文件是否存在(可选,更高效的方式)
local file = io.open(file_path, "r")
if not file then
print("文件不存在,无需删除")
return false
end
file:close()
-- 执行删除操作
local success, err = os.remove(file_path)
if success then
print("文件删除成功")
return true
else
print("文件删除失败:", err)
return false
end
end
delete_file() -- 删除文件
delete_file() -- 再次尝试删除(测试文件不存在的情况)示例2: 二进制文件操作(写入,读取)
lua
local filename = "/spiffs/example.bin"-- 文件路径(可替换为实际路径)
-- 写入二进制文件示例
local function write_binary()
local file = io.open(filename, "wb") -- 二进制写入模式
if not file then
error("无法创建文件: " .. filename)
end
-- 写入固定结构数据
file:write(string.pack(">I4", 0x12345678)) -- 4字节大端整数
file:write(string.pack(">d", 3.1415926535)) -- 8字节双精度浮点
file:write(string.char(0xAB, 0xCD, 0xEF)) -- 自定义字节序列
file:close()
print("二进制文件写入完成")
end
write_binary()-- 执行写入操作
-- 读取二进制文件示例
local function read_binary()
local file = io.open(filename, "rb") -- 二进制读取模式
if not file then
error("无法打开文件: " .. filename)
end
-- 读取并解析数据
local int_data = file:read(4) -- 读取4字节
local num = string.unpack(">I4", int_data)
print("大端整数: 0x" .. string.format("%X", num)) -- 输出: 0x12345678
local float_data = file:read(8)
local pi = string.unpack(">d", float_data)
print("圆周率: " .. string.format("%.9f", pi)) -- 输出: 3.141592654
local bytes = file:read(3)
print("字节序列: " .. string.byte(bytes, 1, 3)) -- 输出: 171
file:close()
end
read_binary()-- 执行读取操作📚 API参考
📋 函数列表
| 函数名 | 功能描述 | 示例 |
|---|---|---|
io.open(filename, [mode]) | 打开文件 | io.open("file.txt", "r") |
io.close([file]) | 关闭文件 | io.close(file) |
📖 io.read(...) | 从标准输入读取 | io.read("*line") |
✏️ io.write(...) | 写入到标准输出 | io.write("Hello") |
🔄 io.flush() | 刷新标准输出缓冲区 | io.flush() |
📥 io.input([file]) | 设置或获取默认输入文件 | io.input("data.txt") |
📤 io.output([file]) | 设置或获取默认输出文件 | io.output("log.txt") |
io.lines([filename, ...]) | 逐行迭代文件内容 | io.lines("file.txt") |
io.popen(prog, [mode]) | 启动程序并连接到其输入/输出 | io.popen("ls") |
io.tmpfile() | 创建临时文件 | io.tmpfile() |
io.type(obj) | 检查对象是否为有效的文件句柄 | io.type(file) |
file:read(...) | 从文件读取 | file:read("*all") |
file:write(...) | 写入到文件 | file:write("data") |
file:lines(...) | 逐行迭代文件内容 | file:lines() |
file:flush() | 刷新文件缓冲区 | file:flush() |
file:seek([whence, offset]) | 设置或获取文件位置 | file:seek("set", 0) |
file:setvbuf(mode, [size]) | 设置文件缓冲模式 | file:setvbuf("no") |
file:close() | 关闭文件 | file:close() |
📦 io.open(filename, [mode])
打开文件
参数:
filename(string): 文件名mode(string, 可选): 打开模式"r": 只读(默认)"w": 只写(创建新文件或清空现有文件)"a": 追加(文件末尾写入)"r+": 读写(文件必须存在)"w+": 读写(创建新文件或清空现有文件)"a+": 读写(追加模式)"rb","wb","ab": 二进制模式
返回值:
file: 文件对象,失败返回nil
示例:
lua
-- 读取文件
local file = io.open("/spiffs/config.txt", "r")
if file then
local content = file:read("*all")
print(content)
file:close()
else
print("无法打开文件")
end
-- 写入文件
local file = io.open("/spiffs/output.txt", "w")
if file then
file:write("Hello World\n")
file:close()
end
-- 二进制文件操作
local bin_file = io.open("/spiffs/data.bin", "rb")
if bin_file then
local data = bin_file:read(1024) -- 读取1024字节
bin_file:close()
end实用例程
lua
local function file_write(file_path, file_data)
print("<名称>"..file_path)
local file = io.open(file_path, "w")-- 以写入模式打开文件(若文件存在则覆盖)
if not file then
print("<名称>")
return
end
file:write(file_data)
file:close()-- 关闭文件句柄
print("<名称>")
end
local function file_read(file_path, file_data)
print("<名称>"..file_path)
local file = io.open(file_path, "r")-- 以读取模式打开文件
local file_data = file:read("*a")
file:close()-- 关闭文件
system.sleep(10)
local success, err = os.remove(file_path)
if success then
print("文件删除成功")
else
print("文件删除失败:", err)
end
return file_data
end
-- 删除文件函数(带错误处理)把上面的地址、主题、引脚替换成你项目里的即可。
📦 io.close([file])
关闭文件
参数:
file(file, 可选): 文件对象,默认为标准输出文件
返回值:
boolean: 成功返回true,失败返回nilstring: 错误信息(失败时)
示例:
lua
-- 关闭特定文件
local file = io.open("/spiffs/data.txt", "r")
if file then
-- 读取文件内容
local content = file:read("*all")
-- 关闭文件
local success, err = io.close(file)
if success then
print("文件已关闭")
else
print("关闭文件失败:", err)
end
end
-- 关闭默认输出文件
io.output():write("一些数据\n")
io.close() -- 关闭默认输出文件📋 io.lines([filename, ...])
逐行迭代文件内容
参数:
filename(string, 可选): 文件名...(可选): 读取格式参数
返回值:
function: 迭代器函数
示例:
lua
-- 迭代文件的每一行
for line in io.lines("/spiffs/data.txt") do
print("行内容:", line)
end
-- 使用不同的读取格式
for line in io.lines("/spiffs/data.txt", "*line") do
print("行:", line)
end📄 io.tmpfile()
创建临时文件
返回值:
file: 临时文件对象
示例:
lua
-- 创建临时文件
local tmp = io.tmpfile()
tmp:write("临时数据\n")
tmp:seek("set", 0) -- 回到文件开始
local content = tmp:read("*all")
print("临时文件内容:", content)
-- 临时文件在程序结束时自动删除🔍 io.type(obj)
检查对象是否为有效的文件句柄
参数:
obj(any): 要检查的对象
返回值:
"file": 开启的文件句柄"closed file": 已关闭的文件句柄nil: 不是文件句柄
示例:
lua
local file = io.open("/spiffs/data.txt", "r")
print(io.type(file)) -- "file"
file:close()
print(io.type(file)) -- "closed file"
print(io.type("not a file")) -- nil
print(io.type(123)) -- nil📖 file:read(...)
从文件读取
参数:
"*all": 读取整个文件"*line": 读取一行"*number": 读取一个数字number: 读取指定字节数
返回值:
string/number: 读取的内容,失败返回nil
示例:
lua
local file = io.open("/spiffs/data.txt", "r")
if file then
-- 逐行读取
for line in file:lines() do
print("行:", line)
end
file:close()
end✏️ file:write(...)
写入到文件
参数:
...(string/number): 要写入的内容
返回值:
file: 文件对象
示例:
lua
local file = io.open("/spiffs/log.txt", "a")
if file then
file:write(os.date(), " - 系统启动\n")
file:close()
end📦 file:close()
关闭文件
返回值:
boolean: 成功返回true,失败返回nilstring: 错误信息(失败时)
示例:
lua
local file = io.open("/spiffs/data.txt", "r")
if file then
-- 读取文件内容
local content = file:read("*all")
print(content)
-- 关闭文件
local success, err = file:close()
if success then
print("文件已关闭")
else
print("关闭文件失败:", err)
end
end📋 file:lines(...)
逐行迭代文件内容
参数:
...(可选): 读取格式参数
返回值:
function: 迭代器函数
示例:
lua
local file = io.open("/spiffs/data.txt", "r")
if file then
-- 迭代文件的每一行
for line in file:lines() do
print("行内容:", line)
end
file:close()
-- 使用不同的读取格式
file = io.open("/spiffs/numbers.txt", "r")
if file then
for number in file:lines("*number") do
print("数字:", number)
end
file:close()
end
end🔄 file:flush()
刷新文件缓冲区
示例:
lua
local file = io.open("/spiffs/log.txt", "w")
if file then
file:write("日志条目1\n")
file:flush() -- 确保数据写入磁盘
file:write("日志条目2\n")
file:flush() -- 确保数据写入磁盘
file:close()
end📍 file:seek([whence, offset])
设置或获取文件位置
参数:
whence(string, 可选): 参考位置"set": 文件开始(默认)"cur": 当前位置"end": 文件末尾
offset(number, 可选): 偏移量,默认为0
返回值:
number: 新的位置nil: 失败string: 错误信息(失败时)
示例:
lua
local file = io.open("/spiffs/data.txt", "r")
if file then
-- 获取当前位置
local pos = file:seek()
print("当前位置:", pos) -- 0
-- 读取一些数据
local data = file:read(10)
pos = file:seek()
print("读取后位置:", pos) -- 10
-- 移动到文件开始
file:seek("set", 0)
pos = file:seek()
print("回到开始位置:", pos) -- 0
-- 从当前位置向前移动5个字节
file:seek("cur", 5)
-- 移动到文件末尾
local end_pos = file:seek("end")
print("文件末尾位置:", end_pos)
file:close()
end⚙️ file:setvbuf(mode, [size])
设置文件缓冲模式
参数:
mode(string): 缓冲模式"no": 无缓冲"full": 全缓冲"line": 行缓冲
size(number, 可选): 缓冲区大小
示例:
lua
local file = io.open("output.txt", "w")
if file then
-- 设置为无缓冲模式(立即写入)
file:setvbuf("no")
file:write("立即写入的数据\n")
-- 设置为行缓冲模式
file:setvbuf("line")
file:write("行缓冲数据")
file:write("\n") -- 这会触发写入
-- 设置为全缓冲模式,指定缓冲区大小
file:setvbuf("full", 1024)
file:write("全缓冲数据...")
file:close()
end🚀 io.popen(prog, [mode])
启动程序并连接到其输入/输出
参数:
prog(string): 程序命令mode(string, 可选): 模式("r"或"w")
返回值:
file: 文件对象
示例:
lua
-- 读取系统命令输出
local file = io.popen("ls -l")
if file then
local output = file:read("*all")
print(output)
file:close()
end
-- 向命令写入数据
local file = io.popen("sort", "w")
if file then
file:write("banana\napple\ncherry\n")
file:close()
end例程
⚠ 文件库(
io.*)需要文件系统支持:仅软PLC模拟器 / 上位机 可用;嵌入式固件(LP3201/LP3202/LP3203/LP3222/LP3232/LP3288 等)通常没有文件系统,io.open会返回nil。下面例程在模拟器/上位机里可直接下载运行,在嵌入式上请改用fdb/ini等内置存储模块。
例程 1:读取配置文件并逐行解析
适用:软PLC模拟器 / 上位机 | 依赖模块:io string | 难度:★☆☆
场景:从 /spiffs/config/device.ini 读一份 key=value 配置,解析成表供脚本使用。
完整代码(可直接下载运行):
lua
local cfg = {}
local f = io.open("/spiffs/config/device.ini", "r")
if not f then
print("配置文件不存在,使用默认值")
else
for line in f:lines() do
local k, v = line:match("^([%w_]+)%s*=%s*(.+)$")
if k then cfg[k] = v end
end
f:close()
end
print("设备名 =", cfg.device_name or "未配置")要点:
io.open(path, "r")读模式;失败返回nil+ 错误信息,必须先判空再使用。f:lines()逐行迭代,省内存;用完f:close()释放句柄(句柄数量有限)。- 用
string.match拆key=value,比string.gmatch更适合单行。
验证方法:
- 在模拟器
/spiffs/config/device.ini写device_name=Line-A,运行打印「设备名 = Line-A」。 - 删掉文件,运行打印「配置文件不存在,使用默认值」「设备名 = 未配置」且不崩溃。
注意事项:
- 嵌入式固件无文件系统,
io.open永远返回nil;别在固件脚本里依赖它。 - 忘记
f:close()会耗尽文件句柄,下次open失败。 - 路径大小写、目录是否存在因平台而异;WIFI 版文件名必须
/spiffs/开头。
例程 2:追加写运行日志
适用:软PLC模拟器 / 上位机 | 依赖模块:io os | 难度:★☆☆
场景:把每次报警/事件带时间戳追加到日志文件,重启后仍在。
完整代码(可直接下载运行):
lua
local log_path = "/spiffs/run.log"
local function log_event(msg)
local f = io.open(log_path, "a") -- "a" = 追加,文件不存在则新建
if not f then print("无法写日志:", msg) return end
f:write(os.date("%Y-%m-%d %H:%M:%S"), " ", msg, "\n")
f:close()
end
log_event("设备启动")
log_event("温度越限 82.3")要点:
- 模式
"a"追加(不覆盖历史);"w"会清空原文件,慎用。 - 每行以
\n结尾,方便后续按行读取。 - 用
os.date打时间戳,便于排查。
验证方法:
- 运行两次,日志文件出现两行带时间戳的记录。
- 把模式改成
"w"再跑:原内容被清空,只剩最后一条。
注意事项:
- 频繁
open/close写小日志效率差;高频日志建议攒一批用table.concat一次性写。 - 日志无限增长会撑满存储,生产环境要按大小/时间滚动或只保留最近 N 行。
- 写失败(磁盘满/只读)
io.open返回nil,务必判空。
例程 3:导出 CSV 数据文件
适用:软PLC模拟器 / 上位机 | 依赖模块:io table string | 难度:★★☆
场景:把采集的温度点导出成 time,value 的 CSV,方便上位机拉走分析。
完整代码(可直接下载运行):
lua
local rows = {
{ "2026-09-25 08:00", 25.6 },
{ "2026-09-25 09:00", 26.1 },
{ "2026-09-25 10:00", 24.8 },
}
local f = io.open("/spiffs/temp.csv", "w")
if f then
f:write("time,value\n")
for _, r in ipairs(rows) do
f:write(r[1], ",", string.format("%.1f", r[2]), "\n")
end
f:close()
print("已导出", #rows, "行")
end要点:
- 先写表头
time,value\n,再逐行时间,数值\n。 - 数值用
string.format("%.1f", v)固定小数位,避免 CSV 里出现25.60000001这类浮点尾。 - 关闭前内容可能在缓冲区,不
close可能丢最后几行。
验证方法:
- 运行后
/spiffs/temp.csv内容为 3 行数据 + 表头。 - 把
rows清空再跑:只剩表头一行,不报错。
注意事项:
- 忘记
f:close()可能导致末尾数据未落盘。 - 用
..在循环里拼超大 CSV 很慢且费内存,用table.concat攒好再一次性write。 - 嵌入式固件不支持,需改用
fdb模块或上位机中转。
最后更新: 2026-04-26版本: 1.0
函数速查表
下表列出本库全部函数与方法(含尚未单独成节的),点「说明」可跳转到对应小节。签名按通用记法:括号内按顺序列全参数,方括号里的可以省略(不传走默认值),... 表示还可继续传同类参数;h: 开头的是对象方法,先用库级函数拿回句柄再冒号调用。
| 方法与签名 | 作用 | 说明 |
|---|---|---|
io.close(…) | 关闭文件句柄 | 本文开头 |
io.flush(…) | 把缓冲区内容立即写入文件 | 本文开头 |
io.input(…) | 设置默认输入文件 | 跳转 |
io.lines(string) | 按行迭代读取文件 | 本文开头 |
io.open(string) | 打开文件(r 读 / w 写 / a 追加,加 + 可双向) | 本文开头 |
io.output(…) | 设置默认输出文件 | 本文开头 |
io.popen(string) | 执行一条命令并返回可读其输出的句柄 | 本文开头 |
io.read(…) | 从文件读取内容 | 本文开头 |
io.tmpfile(…) | 打开一个临时文件 | 本文开头 |
io.type(...) | 检查是否为有效文件句柄 | 本文开头 |
io.write(…) | 向文件写入内容 | 本文开头 |
io.input
- 作用:设置默认输入文件
- 调用形态:
io.input(…)(库级函数) - 参数:无参数
- 可用机型:软 PLC 模拟器 / 上位机