文章目录
- Lua 基础语法
- 单行注释和多行注释
- 数据类型
- 标识符
- 运算符
- 关系运算符
- if条件
- 循环
- while···do
- repeat···until
- 数值for
- 泛型for
- 函数
- 1. 固定参数函数
- 2. 可变参函数
- 3. 多返回值
- 4. 函数作参数
- 5.匿名函数
- Lua 语法进阶
- table
- 1. 数组
- 2. map
- 3. 数组-map 混合结构
- 4. table操作函数
- 迭代器
- 模块
- 元表与元方法
- 1. 两个重要函数
- 2. __index元方法
- 3. __newindex元方法
- 4. 运算符元方法
- 5. __tostring 元方法
- 6. __call 元方法
- 面向对象
- 封装和继承
- 协同线程与协同函数
- 1. 协同线程
- 2. 协同函数
- 文件IO
- 1. 常用静态函数
- 2. 常用实例函数
Lua 基础语法
单行注释和多行注释
两个减号是单行注释;由 --[[ 和 --]] 包裹起来的是多行注释。
-- 单行注释
--[[
多行注释
多行注释
--]]
数据类型
数据类型 | 描述 |
---|---|
nil | 只有值 nil 属于该类,表示一个无效值,与 Java 中的 null 类似。但在条件表达式中相当于 false 。 |
boolean | 包含两个值:false 和 true。 |
number | 表示双精度类型的实浮点数。 |
string | 字符串,由一对双引号或单引号括起来。当一个字符串包含多行 时,可以在第一行中以[[开头,在最后一行中以]]结尾,那么在[[与]]括起来 的这多行内容就是一个字符串。换行符为字符串“\n”。 |
table | 类似于 Java 中的数组,但比数组的功能更强大,更灵活。 |
function | 由 C 或 Lua 编写的函数。 |
thread | 协同线程,是协同函数的执行体,即正在执行的协同函数。 |
userdata | 一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据存储到 Lua 变量中 |
标识符
程序设计语言中的标识符主要包含保留字、变量、常量、方法名、函数名、类名等。Lua的标识符由字母、数字与下划线组成,但不能以数字开头。Lua 是大小写敏感
的。
Lua 常见的保留字共有 22 个。不过,除了这 22 个外,Lua 中还定义了很多的内置全局变量,这些内置全局变量的一个共同特征是,以下划线开头后跟全大写字母。所以我们在定义自己的标识符时不能与这些保留字、内置全局变量重复。
and | break | do | else |
elseif | end | false | for |
function | if | in | local |
nil | not | or | repeat |
return | then | true | until |
while | goto |
运算符
下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为2,B 的值为 5:
操作符 | 描述 | 实例 |
---|---|---|
+ | 加法 | A + B 输出结果 7 |
- | 减法 | A - B 输出结果 -3 |
* | 乘法 | A * B 输出结果 10 |
/ | 除法 | B / A 输出结果 2.5 |
% | 取余 | B % A 输出结果 1 |
^ | 乘幂 | A^2 输出结果 4 |
- | 负号 | -A 输出结果 -2 |
// | 整除运算符(>=lua5.3) | 5//2 输出结果 2 |
关系运算符
下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为10,B 的值为 20:
操作符 | 描述 | 实例 |
---|---|---|
== | 等于,检测两个值是否相等,相等返回 true,否则返回 false | (A == B) 为 false。 |
~= | 不等于,检测两个值是否相等,不相等返回 true,否则返回 false | (A ~= B) 为 true。 |
> | 大于,如果左边的值大于右边的值,返回 true,否则返回 false | (A > B) 为 false。 |
< | 小于,如果左边的值大于右边的值,返回 false,否则返回 true | (A < B) 为 true。 |
>= | 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false | (A >= B) 返回 false。 |
<= | 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false | (A <= B) 返回 true。 |
if条件
Lua 提供了 if…then 用于表示条件判断,其中 if 的判断条件可以是任意表达式。Lua 系统将 false 与 nil 作为假
,将 true 与非 nil 作为真,即使是 0 也是真
。
需要注意,Lua 中的 if 语句的判断条件可以使用小括号括起来,也可以不使用。
-- demo
a=5
if a>0 then
print("num>0")
elseif a==0 then
print("num=0")
else
print("num<0")
end
循环
while···do
a=3
while a>0 do
print(a)
a=a-1
end
repeat···until
-- 类似do···while
a=3
repeat
print(a)
a=a-1
until a<=0
数值for
-- 第一个参数是初始值;第二个是比较值;第三个是步长。不指定步长就为1。
for i=10,50,20 do
print(i)
end
for i=1,3 do
print(i)
end
泛型for
详见:迭代器中的for循环。
函数
1. 固定参数函数
function f(x,y)
print(x,y)
end
f()
f(1)
f(1,2)
f(1,2,3)
2. 可变参函数
function f(...)
print(...)
end
f()
f(1)
f(1,2)
f(1,2,3)
3. 多返回值
function f(...)
return ...
end
a=f()
b=f(1)
c,d=f(1,2)
e,f,g=f(1,2,3)
print(a,b,c,d,e,f,g)
4. 函数作参数
function add( x,y )
return(x+y)
end
function sub( x,y )
return(y-x)
end
function f(m,n,fun)
result=fun(m,n)
print(result)
end
f(1,2,add)
f(1,2,sub)
5.匿名函数
function f(m,n,fun)
result=fun(m,n)
print(result)
end
-- 匿名函数调用
f( 3, 5,function(a,b)
return a*b
end
)
Lua 语法进阶
table
1. 数组
使用 table 可以定义一维、二维、多维数组。不过,需要注意,Lua 中的数组索引是从 1开始
的,且无需声明数组长度
,可以随时增加元素
。当然,同一数组中的元素可以是任意类型
。
-- 一维数组
fruits = {"banana","orange","apple"}
for i=1,3 do
print(fruits[i])
end
-- 二维数组(三行两列)
array={}
for i = 1, 3 do
array[i] = {}
for j = 1, 2 do
array[i][j] = i + j
end
end
for i = 1, 3 do
for j = 1, 2 do
print(array[i][j])
end
end
2. map
使用 table 也可以定义出类似 map 的 key-value 数据结构。其可以定义 table 时直接指定key-value,也可单独指定 key-value。而访问时,一般都是通过 table 的 key 直接访问,也可以数组索引方式来访问,此时的 key 即为索引。
msg={name="bing",age=18,gender="男"}
-- 通过下标操作
msg["depart"]="销售部"
print(msg["depart"])
print(msg["name"])
-- 通过.操作
msg.password="123"
print(msg.password)
print(msg.age)
-- 定义一个map key为表达式
a="aaa_"
b=3
c=4
m={
[a.."bbb"]=true,
[b+c]=7
}
print(m.aaa_bbb)
print(m[7])
3. 数组-map 混合结构
Lua 允许将数组与 key-value 混合在同一个 table 中进行定义。key-value 不会占用数组的数字索引值。
msg={"北京",name="bing",age=18,"上海",gender="男","广州"}
for i=1,3 do
print(msg[i])
end
students={
{name="张三",age=20},
{name="李四",age=21},
{name="王五",age=22}
}
for i=1,3 do
print(students[i].name.." : "..students[i].age)
end
4. table操作函数
Lua 中提供了对 table 进行操作的函数。
-
table.concat()
table.concat (table , sep , start , end)该函数用于将指定的 table 数组元素进行字符串连接。连接从 start 索引位置到 end索引位置的所有数组元素, 元素间使用指定的分隔符 sep 隔开。如果 table 是一个混合结构,那么这个连接与 key-value 无关,仅是连接数组元素。
msg={"北京",name="bing",age=18,"上海",gender="男","广州"} print(table.concat(msg)) print(table.concat(msg,",")) print(table.concat(msg,",",2)) print(table.concat(msg,",",1,2))
-
table.unpack()
table.unpack (table , i , j)拆包。该函数返回指定 table 的数组中的从第 i 个元素到第 j 个元素值。i 与 j 是可选的,默认 i 为 1,j 为数组的最后一个元素。Lua5.1 不支持该函数。
msg={"北京","上海","广州","深圳"} print(table.unpack(msg)) print(table.unpack(msg,2)) print(table.unpack(msg,2,3))
-
table.pack()
table.pack (…)打包。该函数的参数是一个可变参,其可将指定的参数打包为一个 table 返回。这个返回的 table 中具有一个属性 n,用于表示该 table 包含的元素个数。Lua5.1 不支持该函数。
tmp=table.pack("banana","orange","apple") print(tmp.n) print(table.concat(tmp,","))
-
table.maxn()
table.maxn(table)该函数返回指定 table 的数组中的最大索引值,即数组包含元素的个数。Lua 5.2及以上版本中,table.maxn()函数已被废弃,不再被支持。
msg={"北京","上海","广州","深圳"} print(#msg) -- 被弃用 -- print(table.maxn(msg))
-
table.insert()
table.insert (table, [pos],value)。该函数用于在指定 table 的数组部分指定位置 pos 插入值为 value 的一个元素。其后的元素会被后移。pos 参数可选,默认为数组部分末尾。
msg = {"北京", "上海", "广州"} table.insert(msg, "深圳") print(table.concat(msg, ",")) table.insert(msg, 2, "江西") print(table.concat(msg, ","))
-
table.remove ()
table.remove (table,[pos])该函数用于删除并返回指定 table 中数组部分位于 pos 位置的元素。其后的元素会被前移。pos 参数可选,默认删除数组中的最后一个元素。
msg = {"北京","江西","上海","广州","深圳"} table.remove(msg) print(table.concat(msg, ",")) table.remove(msg, 2, "江西") print(table.concat(msg, ","))
-
table.sort()
table.sort(table , [fun(a,b)])。该函数用于对指定的 table 的数组元素进行升序排序,也可按照指定函数 fun(a,b)中指定的规则进行排序。fun(a,b)是一个用于比较 a 与 b 的函数,a 与 b 分别代表数组中的两个相邻元素。
注意:
-
如果 arr 中的元素既有字符串又有数值型,那么对其进行排序会报错。
-
如果数组中多个元素相同,则其相同的多个元素的排序结果不确定,即这些元素的索引
-
如果数组元素中包含 nil,则排序会报错。
msg = {6, 2, 7, 4, 1, 9} -- 默认升序 table.sort(msg) print(table.concat(msg, ",")) table.sort(msg,function(a,b) return a > b end ) print(table.concat(msg, ","))
-
迭代器
Lua 提供了两个迭代器 pairs(table)与 ipairs(table)。这两个迭代器通常会应用于泛型 for循环中,用于遍历指定的 table。这两个迭代器的不同是:
-
ipairs(table):仅会迭代指定 table 中的数组元素。
-
pairs(table):会迭代整个 table 元素,无论是数组元素,还是 key-value。
msg={"北京",name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 迭代数组元素
for i,v in ipairs(msg) do
print(i,v)
end
msg={"北京",name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 迭代所有元素
for k,v in pairs(msg) do
print(k,v)
end
模块
模块是Lua中特有的一种数据结构。从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
模块文件主要由 table 组成。在 table 中添加相应的变量、函数,最后文件返回该 table即可。如果其它文件中需要使用该模块,只需通过 require 将该模块导入即可。
-- myModule.lua
-- 申明一个模块
local myModule = {}
-- 为模块添加一个变量
myModule.pi = 3.14
-- 为模块添加一个函数 (求矩形周长)
function myModule.perimeter(a, b)
return (a + b) * 2
end
-- 为模块添加一个匿名函数 (求矩形面积)
myModule.area = function(a, b)
return a * b
end
--=============== 定义一些与模块无关的内容 ===============--
-- 定义一个全局变量
goldenRatio = 0.618
-- 定义一个局部函数 (求圆的面积)(外部不能使用模块内部的局部变量和函数)
local function circleArea(r)
return myModule.pi * r * r
end
-- 定义一个全局函数 (求矩形中最大圆的面积)
function maxArea(a, b)
local r = math.min(a, b)
return circleArea(r)
end
-- demo1.lua
require "myModule"
print(myModule.pi)
print(myModule.perimeter(3,5))
print(myModule.area(3,5))
print(goldenRatio)
print(maxArea(3,5))
元表与元方法
元表
,即 Lua 中普通 table 的元数据表
,而元方法
则是元表中定义的普通表的默认行为
。Lua 中的每个普通 table 都可为其定义一个元表,用于扩展该普通 table 的行为功能。例如,对于 table 与数值相加的行为,Lua 中是没有定义的,但用户可通过为其指定元表来扩展这种行为;再如,用户访问不存在的 table 元素,Lua 默认返回的是 nil,但用户可能并不知道发生了什么。此时可以通过为该 table 指定元表来扩展该行为:给用户提示信息,并返回用户指定的值。
1. 两个重要函数
元表中有两个重要函数:
-
setmetatable(table,metatable):将 metatable 指定为普通表 table 的元表。
-
getmetatable(table):获取指定普通表 table 的元表。
2. __index元方法
当用户在对 table 进行读取
访问时,如果访问的数组索引或 key 不存在
,那么系统就会自动调用元表的 __index
元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写的 __index 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil。
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 返回nil
print(msg.xxx)
-- 声明一个元表
meta={}
-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)
-- 重写__index方法
meta.__index=function(tab,key)
return "通过【"..key.."】访问的值不存在"
end
print(msg.xxx)
print(msg[2])
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 声明一个元表
meta={}
-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)
-- 定义另一个表
other={}
other[6]="江西"
other.xxx="湖北"
-- 重写__index方法
-- 如果在msg中找不到相关信息,则会去other表中查找
meta.__index=other
print(msg[6])
print(msg.xxx)
3. __newindex元方法
当用户为 table 中一个不存在的索引或 key 赋值
时,就会自动调用元表的 __newindex
元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写 __newindex 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil。
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 声明一个元表
meta={}
-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)
-- 重写__index方法
meta.__newindex=function(tab,key,value)
print("新增的key为: "..key.." 新增的value为: "..value)
-- 将新增的key-value写入到原始表
rawset(tab,key,value)
end
msg.xxx="江西"
print(msg.xxx)
msg[6]="湖北"
print(msg[6])
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 声明一个元表
meta={}
-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)
-- 定义另一个表
other={}
-- 重写__index方法
-- 会将新增的数据写入other这个table中
meta.__newindex=other
msg.xxx="江西"
print(msg.xxx)
print(other.xxx)
4. 运算符元方法
如果要为一个表扩展加号(+)、减号(-)、等于(==)、小于(<)等运算功能,则可重写相应的元方法。例如,如果要为一个 table 扩展加号(+)运算功能,则可重写该 table 元表的__add 元方法,而具体的运算规则,则是定义在该重写的元方法中的。这样,当一个 table 在进行加法(+)运算时,就会自动调用其元表的__add 元方法。
元方法 | 说明 | 元方法 | 说明 |
---|---|---|---|
__add | 加法,+ | __band | 按位与,& |
__sub | 减法,- | __bor | 按位或,| |
__mul | 乘法,* | __bxor | 按位异或,~ |
__div | 除法,/ | __bnot | 按位非,~ |
__mod | 取模,% | __shl | 按位左移,<< |
__pow | 次幂,^ | __shr | 按位右移,>> |
__unm | 取反,- | ||
__idiv | 取整除法,// | __eq | 等于,== |
__lt | 小于,< | ||
__concat | 字符串连接,.. | __le | 小于等于,<= |
__len | 字符串长度,# |
msg={"北京",17,name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 声明一个元表
meta={
__add=function(tab,num)
-- 遍历table中的所有元素
for k,v in pairs(tab) do
if type(v)=="string" then
tab[k]=tab[k]..num
elseif type(v)=="number" then
tab[k]=tab[k]+num
end
end
-- 返回变化过的tab
return tab
end
}
-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)
sumMsg=msg+3
for key,value in pairs(msg) do
print("key: "..key.." value: "..value)
end
5. __tostring 元方法
直接输出一个 table,其输出的内容为类型与 table 的存放地址。如果想让其输出 table中的内容,可重写 __tostring 元方法。
msg={"北京",17,name="bing","深圳",age=18,"上海",gender="男","广州"}
-- 声明一个元表
meta={
__add=function(tab,num)
-- 遍历table中的所有元素
for k,v in pairs(tab) do
if type(v)=="string" then
tab[k]=tab[k]..num
elseif type(v)=="number" then
tab[k]=tab[k]+num
end
end
-- 返回变化过的tab
return tab
end, -- 当有多个元方法时,一定要用" , "隔开
__tostring=function(tab)
-- 做一个字符串拼接
str=""
for key,value in pairs(msg) do
str=str..key..":"..value.." "
end
return str
end
}
-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)
-- 会输出table中的内容
print(msg)
6. __call 元方法
当将一个 table 以函数形式来使用时,系统会自动调用重写的 __call 元方法。该用法主要是可以简化对 table 的相关操作,将对 table 的操作与函数直接相结合。
msg={"北京",17,name="bing","深圳",age=18,"上海","广州"}
-- 将msg与匿名元表关联起来
setmetatable(msg, {
__tostring=function(tab)
-- 做一个字符串拼接
str=""
for key,value in pairs(msg) do
str=str..key..":"..value.." "
end
return str
end,
__call=function(tab,str,num)
-- 遍历table
for k,v in pairs(msg) do
if type(v)=="string" then
tab[k]=v..str
elseif type(v)=="number" then
tab[k]=v+num
end
end
return tab
end
})
msg("-hello",3)
print(msg)
面向对象
Lua 中没有类的概念,但通过 table、function 与元表可以模拟和构造出具有类这样功能的结构。
封装和继承
-- 创建一个学生类
Student = {}
-- 定义学生类的构造函数
function Student:new(name, age, gender)
local obj = {
name = name,
age = age,
gender = gender
}
-- 将对象的属性保存在obj中,并将obj设置为对象的元表。这样,当我们访问对象的属性时,可以通过元表的__index字段来查找。
setmetatable(obj, { __index = self })
return obj
end
-- 定义学生类的方法
function Student:getName()
return self.name
end
function Student:getAge()
return self.age
end
function Student:getGender()
return self.gender
end
-- 创建一个研究生类
GraduateStudent = {}
-- 设置研究生类的元表为学生类,以实现继承
setmetatable(GraduateStudent, { __index = Student })
-- 定义研究生类的构造函数
function GraduateStudent:new(name, age, gender, major)
local obj = Student:new(name, age, gender) -- 调用父类的构造函数
obj.major = major -- 添加研究生类特有的属性
setmetatable(obj, { __index = self })
return obj
end
-- 定义研究生类的方法
function GraduateStudent:getMajor()
return self.major
end
-- 创建学生对象
local student1 = Student:new("Alice", 18, "Female")
-- 创建研究生对象
local graduateStudent = GraduateStudent:new("Bob", 20, "Male", "Computer Science")
-- 调用学生对象的方法
print(student1:getName()) -- 输出:Alice
print(student1:getAge()) -- 输出:18
print(student1:getGender()) -- 输出:Female
-- 调用研究生对象的方法
print(graduateStudent:getName()) -- 输出:Bob
print(graduateStudent:getAge()) -- 输出:20
print(graduateStudent:getGender()) -- 输出:Male
print(graduateStudent:getMajor()) -- 输出:Computer Science
首先创建了一个空的 Student
表,它作为学生类的原型。然后,定义了一个 new
方法作为构造函数,用于创建学生对象。在构造函数中,我们使用 setmetatable
将新创建的对象(obj)与学生类关联起来,将元表的 __index
元方法设置为学生类本身。在构造函数中,我们还初始化了学生对象的属性。接下来,我们定义了一些用于访问学生对象属性的方法,例如 getName
、getAge
和 getGender
。这些方法可以通过对象的冒号语法进行调用。
然后将研究生类的元表设置为学生类,这样研究生对象就可以继承学生对象的方法。然后,在研究生类的构造函数中,我们调用了父类的构造函数,并添加了研究生类特有的属性。对于研究生对象,除了继承学生对象的属性和方法外,我们还可以调用 getMajor
方法来获取研究生特有的属性。
协同线程与协同函数
1. 协同线程
Lua 中有一种特殊的线程,称为 coroutine,协同线程,简称协程。其可以在运行时暂停执行,然后转去执行其它线程,然后还可返回再继续执行没有执行完毕的内容。即可以“走走停停,停停再走走”。协同线程也称为协作多线程,在 Lua 中表示独立的执行线程。任意时刻只会有一个协程执行,而不会出现多个协程同时执行的情况。协同线程的类型为 thread,其启动、暂停、重启等,都需要通过函数来控制。下表是用于控制协同线程的基本方法。
方法 | 描述 |
---|---|
create(function) | 创建一个协同线程实例,即返回的是 thread 类型。参数是一个function。其需要通过 resume()来启动协同线程的执行 |
resume(thread, …) | 启动指定的协同线程的执行,使其从开始处或前面挂起处开始执行。可以向 create()的内置函数传递相应的参数。如果内置函数具有返回值,resume()会全部接收并返回。 |
running() | 返回正在运行的协同线程实例,即 thread 类型值 |
yield() | 挂起协同线程,并将协同线程设置为挂起状态。resume()可从挂起处重启被挂起的协同线程 |
status(thread) | 查看协同线程的状态。状态有三种:运行态 running,挂起态 suspended,消亡态 dead |
close() | 关闭协同线程 |
wrap(function) | 创建一个协同函数,返回的是 function 类型。一旦调用该函数就会创建并执行一个协同线程实例 |
-- 创建一个协同线程的实例
co = coroutine.create(
function(a,b)
print(a+b,b-a)
-- 查看协同线程的类型
thread=coroutine.running()
print("协同线程的类型是: "..type(thread))
-- 查看协同线程的状态
print("协同线程的状态:",coroutine.status(co))
-- 挂起协同线程,并将返回值传递给主线程
coroutine.yield(a*b,b+1)
-- 当协同线程重新返回时会输出下面的语句
print("协同线程重新返回了")
end
)
-- 启动协同线程,等协同线程挂起的时候接收协同线程的返回值
success,res1,res2=coroutine.resume(co,3,5)
print("返回值:",success,res1,res2)
-- 查看在主线程中co的状态
print("协同线程的状态:",coroutine.status(co))
-- 重新启动协同线程
coroutine.resume(co)
-- 最后查看协同线程的状态
print("协同线程的状态:",coroutine.status(co))
2. 协同函数
协同线程可以单独创建执行,也可以通过协同函数的调用启动执行。使用 coroutine 的wrap()函数创建的就是协同函数,其类型为 function。由于协同函数的本质就是函数,所以协同函数的调用方式就是标准的函数调用方式。只不过,协同函数的调用会启动其内置的协同线程。
-- 创建一个协同函数的实例
cf = coroutine.wrap(
function(a,b)
print(a+b,b-a)
-- 挂起协同线程,并将返回值传递给主线程
coroutine.yield(a*b,b+1)
-- 当协同函数重新返回时会输出下面的语句
print("协同函数重新返回了")
return b/a
end
)
-- 启动协同函数,等协同函数挂起的时候接收协同函数的返回值
res1,res2=cf(2,4)
print("返回值:",res1,res2)
-- 重新启动协同函数
res=cf()
print(res)
文件IO
Lua 中提供了大量对文件进行 IO 操作的函数。这些函数分为两类:静态函数与实例函数。所谓静态函数是指通过 io.xxx()方式对文件进行操作的函数,而实例函数则是通过 Lua中面向对象方式操作的函数。
-
io.open(filename , mode)
其中,filename 是要打开的文件名,可以是相对路径或绝对路径。mode 是一个可选参数,用于指定打开文件的模式,默认为只读模式(“r”)。
mode参数可以是以下值之一:
"r"
:只读模式(默认值),打开文件用于读取。"w"
:写入模式,打开文件用于写入。如果文件已存在,则清空文件内容;如果文件不存在,则创建新文件。"a"
:追加模式,打开文件用于写入。如果文件已存在,则在文件末尾追加内容;如果文件不存在,则创建新文件。"b"
:二进制模式,打开文件以二进制模式进行读取或写入。"+"
:更新模式,打开文件用于读取和写入
-
io.input(file)
指定要读取的文件。
-
io.output(file)
指定要写入的文件。
-
io.read(format)
以指定格式读取 io.input()中指定的输入文件。其中 format 格式有:
*l
:从当前位置的下一个位置开始读取整个行,默认格式*n
:读取下一个数字,其将作为浮点数或整数a
:从当前位置的下一个位置开始读取整个文件number
:这是一个数字,表示要读取的字符的个数
-
io.write(data)
将指定的数据 data 写入到 io.output()中指定的输出文件。
1. 常用静态函数
-- demo2.lua
-- 以只读方式打开一个文件
file=io.open("info.txt","r")
-- 指定要读取的文件
io.input(file)
-- 读取一行数据
line=io.read("*l")
while line ~= nil do
print(line)
line=io.read("*l")
end
-- 关闭文件
io.close(file)
-- demo3.lua
-- 以读写方式打开文件
file=io.open("info.txt","a+")
-- 指定写入的文件
io.output(file)
-- 写入数据
io.write("gender=male\n")
-- 关闭文件
io.close(file)
2. 常用实例函数
-
file:read()
这里的 file 使用的是 io.open()函数返回的 file,其实际就是 Lua 中的一个对象。其用法与 io.read()的相同。
-
file:write()
用法与 io.write()的相同。
-
file:seek(whence , offset)
该函数用于获取或设置文件读写指针的当前位置。位置从 1 开始计数,除文件最后一行外,每行都有行结束符,其会占两个字符位置。位置 0 表示文件第一个位置的前面位置。当 seek()为无参时会返回读写指针的当前位置。参数 whence 的值有三种,表示将指针定位的不同位置。而 offset 则表示相对于 whence 指定位置的偏移量,offset 的默认值为 0,为正表示向后偏移,为负表示向前偏移。
set:表示将指针定位到文件开头处,即 0 位置处
cur:表示指针保持当前位置不变,默认值
end:表示将指针定位到文件结尾处
-- 以只读的方式打开文件
file=io.open("nums.txt","r")
-- 查看当前指针的位置
pos=file:seek()
print(pos) -- 0
-- 读取一行数据
line=file:read("*l")
print(line) -- 12345
-- 查看当前指针位置
pos=file:seek()
print(pos) -- 6
-- 设置指针的位置到起始位置
pos=file:seek("set")
print(pos) -- 0
-- 设置指针的位置为10
pos=file:seek("set",10)
-- 读取一行数据
line=file:read("*l")
print(line) -- 90
-- 设置指针到文件的末尾
pos=file:seek("end")
print(pos) -- 13
-- 关闭文件
file:close()