Lua标准库

Lua的标准库能与C语言的API直接实现

  • 基础函数库
  • 协程库
  • string库
  • table库
  • math库
  • io库
  • 操作系统库
  • debug库

http://cloudwu.github.io/lua53doc/manual.html#6.4

string库

字符串处理库提供了字符串处理的通用函数,如字符串查找、子串、模式匹配等。当在Lua中对字符串作索引时,第一个字符从1开始计算,而不是C语言中的0。索引可以是负数,表示从字符串末尾反向解析。也就是说,最后一个字符在-1位置上。

字符串库中的所有函数都在表string中,它还将其设置为字符串元表的__index域。因此,可以以面向对象的方式使用字符串函数。

  • Lua中没有字符串类型,Lua的string类型表示字符序列。
  • string字符序列中字符采用8位编码,可存放任意二进制数据。
  • string是不可变的值,修改后会返回新string,原有string保持不变。
  • string字面值采用单引号或双引号包裹
  • string使用[[]]界定字符串
  • Lua提供运行时数字和字符的自动转换
  • 长度操作符#可获取字符串的长度即字符个数

原始Lua解释器操作字符串的能力有限,只能创建字符串常量、连接字符串、获取字符串长度。无法提取子串或检索字符串内容。Lua中字符串操作能力源于string库。

基础字符串函数

  • string.len(str) 获取字符串的长度
local str = "hi lua\t, what\n lua\000"
print(string.len(str), #str) --19 19
  • string.rep(str, n) 字符串重复n次并拼接返回
local str = "-"
local result = string.rep(str,10)
print(result)-- ----------
  • string.lower(str) 字符串转小写
local str = "String.Lower"

local result = string.lower(str)
print(result) -- string.lower

local result = string.upper(str)
print(result) -- STRING.LOWER

local result = string.reverse(str)
print(result) -- rewoL.gnirtS
  • string.sub(str, begin[, end]) 截取字符串
local str = "[this is a island]"
local result = string.sub(str, 2, -2)
print(str, result) 
-- [this is a island]
-- this is a island

对字符串数组排序且不区分大小写

local arr = {"Alice", "Mary", "carl", "Fifi", "jay"}
table.sort(arr, function(x,y)
    return string.lower(x) < string.lower(y)
end)
print(table.concat(arr,",")) --Alice,carl,Fifi,jay,Mary
  • string.char(...) 将数字编码转换为字符串
print(string.char(97, 100, 101)) --ade
  • string.byte(...) 将字符转换为数字
print(string.byte("abc", 3)) --99
print(string.byte("abcde", 3, 5)) -- 99 100 101
  • string.format(format, ...) 格式化字符串
print(string.format("pi = %.4f", math.pi)) -- pi = 3.1416
print(string.format(
    "%4d-%02d-%02d %02d:%02d:%02d", 
    os.date("%Y"), 
    os.date("%m"), 
    os.date("%d"),
    os.date("%H"),
    os.date("%M"),
    os.date("%S")
))
-- 2018-12-07 23:45:02

模式匹配函数

Lua中的匹配模式直接用常规的字符串来描述,用于模式匹配函数string.findstring.matchstring.gmatchstring.gsub

Lua即没有使用POSIX也没有使用Perl正则表达式来进行模式匹配,其原因主要是考虑到Lua的大小。

Lua中的模式匹配字符串,用来表示一个字符集合,可组合使用。

  • x 表示字符x自身
  • . 点表示任何字符
  • %a 表示任何字母
  • %c 表示任何控制字符
  • %d 表示任何数字
  • %g 表示任何除空白符外的可打印字符
  • %l 表示所有小写字母
  • %p 表示所有标点符号
  • %s 表示所有空白字符
  • %u 表示所有大写字母
  • %w 表示所有字母及数字
  • %x 表示所有16进制数字符号
  • %X X表示任意非字母或数字的字符

所有单个字母表示的类别,若将字母改为大写均表示对应的补集。如何定义字母、空格、其他字符组取决于当前的区域设置。

  • string.find(str, pattern, [, init [, plain]]) 用于在一个给定的目标字符串中搜索一个模式,匹配与自己完全相同的拷贝。当匹配成功后会返回两个值:匹配到的起始索引和结尾索引,若没有匹配到则返回nil
    参数1:str表示给定的目标字符串
    参数2: pattern表示待匹配的字符串
    参数3:init表示从哪里开始搜索,默认值为1,可为负数。
    参数4:plaintrue表示关闭模式匹配机制,此时函数仅做直接的查找字符子串操作,但pattern中没有字符被看作魔法字符。注意如果给定了plain则必须填写init
local str = "this is a island"
local x,y = string.find(str, "is")
print(x, y) -- 3 4

在字符串中所有换行符的位置创建表

local str = "this\nis\na\nisland"
local tbl = {}
local i = 0
while true do
    i = string.find(str, "\n", i+1)
    if i==nil then
        break
    end
    tbl[#tbl + 1] = i
end
print(table.concat(tbl,","))-- 5,8,10
local pair = "name = Anna"
local start,stop,key,val = string.find(pair, "(%a+)%s*=%s*(%a+)")
print(start, stop ,key, val)-- 1    11  name    Anna
  • string.match(str, pattern, [, init]) 在目标字符串str中找到第一个能用pattern匹配到的部分,若找到则match返回其中捕获的字符串,否则返回nil。若pattern中未指定捕获则返回整个pattern捕获到的字符串。可选参数init表示从哪里开始搜索默认为1可为负数。
local str = "today is 2018-12-08"
local year,month,day = string.match(str, "(%d+)-(%d+)-(%d+)")
print(year, month, day)--2018   12  08
  • string.gsub(str, pattern, replacement, [, n]) 全局(global)替换子字符串

参数:
参数1:str 源字符串
参数2:pattern 匹配模式
参数3:将匹配模式pattern匹配到的字符串替换为replacement
参数4:n可选表示只看源字符串的前n个字符

返回值
返回值1:替换后的字符串
返回值2:替换的次数

function trim(str)
    return (string.gsub(str, "^%s*(.-)%s*$", "%1"))
end

print(trim("\t jun chow ")); -- jun chow

math库

数学库
-- 获取圆周率
print(math.pi) -- 3.1415926535898
-- 获取Lua可表示最大数字
print(math.huge) -- inf

-- 设置随机种子,在使用math.random函数前必须先设置。
print(math.randomseed(os.time()))
-- 生成0到1之间的随机数
print(math.random()) -- 0.001251220703125
-- 生成1到100之间的随机数
print(math.random(100)) -- 57
-- 生成6位随机数
print(math.random(100000, 999999)) -- 273968

table库

Lua中table表具有以下特性

  • table表是一个关联数组,数组的索引可以是数字或字符串。
  • table表默认初始索引以1开始
  • table表的变量是一个地址引用,对table的操作不会产生数据影响。
  • table表可自动扩容

table库由辅助函数构成,默认会将table作为数组来操作。

表库
  • table.concat(table, separator, start, end)
  • table.insert(table, position, value)
  • table.remove(table, position)
  • table.sort(table, compare)

table.insert(table, position, value)

用于将元素value插入到数组table的指定位置position,会移动后续元素以腾出空间。其中位置参数position为可选,默认为数组末尾。

local tbl = {"alpha", "beta", "gamma"}
table.insert(tbl, "delta")
table.insert(tbl, "epsilon")
table.insert(tbl, "zeta")
print(table.concat(tbl, ","))-- alpha,beta,gamma,delta,epsilon,zeta
local tbl = {1, 2, 3}
table.insert(tbl, 1, 10)
for i,v in ipairs(tbl) do
    print(i,v)-- 10 1 2 3
end

table.remove(table, position)

删除并返回table数组指定位置position上的元素,并将该位置之后的所有元素前移,以填补空隙。如果在调用此函数时不指定位置position参数,则会删除数组的最后一个元素。

local tbl = {"alpha", "beta", "gamma"}
table.remove(tbl)
print(table.concat(tbl, ","))-- alpha,beta

table.concat(table, separator, start, end)

table.concat接收一个字符串数组并返回字符串连接后的结果。列出参数中指定数组table从开始位置start到结束位置end的所有元素,元素间以指定分隔符separator隔开。除了table外,其他参数都不是必须的,分隔符separator默认是空字符,开始位置start默认为1,结束位置end默认为数组的长度。

local tbl = {"alpha", "beta", "gamma"}
print(table.concat(tbl)) --alphabetagamma
print(table.concat(tbl,","))--alpha,beta,gamma
print(table.concat(tbl, 2, 3))-- gamma

扩展table.concat使其能处理嵌套的字符串数组

function concat(tbl)
    if type(tbl)~="table" then
        return tbl
    end
    local result = {}
    for i=1,#tbl do
        result[i] = concat(tbl[i])
    end
    return table.concat(result)
end
-- test
local arr = {
    {"a", {" nice "}},
    "and",
    {{" long "}, "list"}
}
print(concat(arr))--a nice and long list

table.sort(table, compare)

table.sort()函数对给定的table进行升序排序,其中compare为可选参数,可以是一个外部函数用来自定义排序标准。排序函数的标准是接收两个参数并返回一个布尔型的值,若布尔值为true则表示升序否则则为降序。

table中索引是一个无序的集合,若要对其进行排序则必 须将其复制到一个数组中,然后对数组元素进行排序。值得注意的,对于Lua而言,数组也是无序的,它们的本质都是table

-- 对键名进行排序的迭代器
function pairsByKeys(tbl, fn)
    -- 获取键名
    local result = {}
    for k,v in pairs(tbl) do
        result[#result + 1] = k
    end
    -- 对键名进行排序
    table.sort(result, fn)
    -- 迭代器
    local i = 0 --迭代器变量
    return function()
        i = i + 1
        return result[i], tbl[result[i]]
    end
end
-- test
local fns = {
    set=10,
    get=100,
    count=29
}
for index,value in pairsByKeys(fns) do
    print(index, value)
end
--[[
count   29
get 100
set 10
--]]

操作系统库

Lua操作系统库函数,包含了文件管理、系统时钟等于操作系统相关信息,这些函数定义在表os中。

操作系统库

日期时间

  • os.clock() 返回程序使用CPU时间的近似值
  • os.time([table]) 默认获取当前时间戳,可指定日期时间的table参数。
  • os.date([format [, time]]) 格式化时间戳为可读时间,time为可选默认省略时为当前时间戳。
  • os.difftime(ts2, ts1) 返回时间戳ts1到时间戳ts2相差的秒数

os.clock()

  • os.clock() 返回程序使用CPU时间的近似值
print(os.clock(), string.format("%.2f", os.clock())) -- 0.0 0.00

计算程序执行消耗的CPU秒数

local clock_begin = os.clock()

local sum = 0
for i=1, 1000000 do
    sum = sum + i
end

local clock_end = os.clock()
print(string.format("elapsed seconds is %.2f\n", clock_end - clock_begin))
-- elapsed seconds is 0.02
  • os.clock() 的实现是调用C语言的函数库,其中CLOCKS_PER_SEC值在不同平台有着不同定义。
static int os_clock(lua_State *L){
  lua_pushnumber(L, (lua_Number))/(lua_Number)CLOCKS_PER_SEC;
  return 1;
}
  • 可使用socket库的socket.gettime()替代os.clock()
require "socket"
local time = socket.gettime()
  • 要注意函数的溢出问题,程序运行时间太长的话,使用clock有可能返回负数。

os.time([table])

table内容返回一个数字时间值,若无参数则返回当前时间table的字段。返回一个指定时间点的UNIX时间戳,若无参数调用则返回当前时间点的UNIX时间戳。

-- 获取当前UNIX的10位秒级时间戳
print(os.time()) -- 1544030239

-- 获取指定日期时间的时间戳
os.time({year=2018, month=06, day=05, hour=12, min=23, sec=45, isdst=true})

os.date([format [, time]])

os.dateos.time的反函数,将一个UNIX时间戳装换成可读的字符串形式。若省略第二个参数time则默认返回当前时间点的日期。返回按format格式化后的日期、时间的字符串或表。若设置time参数,则按time指定的时间格式进行格式化,否则按当前时间格式化。

print(os.date()) -- 12/06/18 01:21:35
print(os.date("%Y-%m-%d %H:%M:%S")) -- 2018-12-06 01:22:06

参数说明:

format 参数为空则按当前系统的设置返回格式化后的字符串,为了生成日期的table可使用格式字符串*t

  • ! 按格林威治时间进行格式化
  • *t 返回带4位年、1-12的月份,1-31的日期、0-23的小时数、0-59分钟数、 0-61秒数、1-7星期数
local tbl = os.date("*t", os.time())
for k,v in pairs(tbl) do
    print(k, v)
end
--[[
yday    340
year    2018
sec 21
day 6
month   12
hour    1
min 25
isdst   false
wday    5
--]]

os.date会将日期格式化为一个字符串,此字符串是传入格式字符串的副本,其中某些特殊表被替换成时间和日期信息,所有标记都以%开头,并伴随一个字符。

%a 一个星期中天数的简写
%A 一个星期找那个天数的全称
%b 月份简写
%B 月份全称
%c 日期和时间
%d 一个月中的第几天
%H 24小时制中的小时数
% I 12小时制中的小时数
%j 一年中的第几天
%M 分钟数
%m 月份数
%P 上午am或下午pm
%S 秒数
%w 一星期中的第几天
%W 一年中第几个星期
%x 日期
%X 时间
%y 两位数的年份
%Y 完整的年份
%% 字符串%

时间戳转为日期

function ts2date(ts)
    local tbl = {}
    local date = string.format(os.date("%x", ts))
    local arr = string.split(date, "/")
    tbl.YEAR = checkint(arr[3])
    tbl.MONTH = checkint(arr[1])
    tbl.DAY = checkint(arr[2])
    return tbl
end

计算时间戳间隔天数

function diff_days(mints, maxts)
    local temp = nil
    if maxts<mints then
        temp = mints
        mints = maxts
        maxts = temp
    end
    return checkint(maxts/86400) - checkint(mints/86400)
end

os.difftime(t2, t1)

返回时间戳ts1到ts2相差的秒数,可用于计算代码的执行时长。

local ts1 = os.time()
for i=0,10000000 do
  math.random()
end
local ts2 = os.time()

print(os.difftime(ts2, ts1)) --1.0

系统调用

os.execute([command])

系统级的函数调用os.execute相当于·C语言中的system(),函数有缺省的参数command,函数是解析command后在通过系统来调用解析的结果,返回一个依赖于操作系统的状态码。当参数缺省时,若操作系统可以调用解析参数则返回非0的数否则返回0。

local ret = os.execute()
if ret ~= 0 then
  os.execute("color 02") -- 将命令行的颜色由白色修改为绿色
  os.execute("copy test.lua test.lua.bak")
  os.execute("pause")
end

os.exit(code)

按任意键继续...,相当于C语言中的exit函数,终止主程序,code为返回值。

-- 结束程序并返回状态码,0代表成功。
print("run then exit")
os.exit(0) 
print("can't output")
-- run then exit

os.setlocale(locale[, category])

设置程序本地配置,函数返回最新配置,若失败则返回nil

os.setlocale("zh_CN.utf8", "time")
print(os.date())

local 指定当前配置名称的字符串

  • "" 空字符串表示当前配置被视为本地配置
  • "c" 表示当前配置被视为标准C配置
  • nil 返回category设置的配置名称的当前值

category 描述待更改的配置名称

  • all
  • collate
  • ctype
  • monetary
  • numeric
  • time

os.getenv(varname)

返回当前进程的环境变量varname(不区分大小写)的值,若变量没有定义时返回为nil

-- 获取操作系统名称
print(os.getenv("OS")) -- Windows_NT
-- 获取系统用户名
print(os.getenv("USERNAME")) -- jc
-- 获取当前登录服务器名称
print(os.getenv("LOGONSERVER")) -- \\WIN10-JC
-- 获取用户域名
print(os.getenv("USERDOMAIN")) -- WIN10-JC
-- 获取计算机名称
print(os.getenv("COMPUTERNAME")) -- WIN10-JC

-- 获取处理器cpu数量
print(os.getenv("NUMBER_OF_PROCESSORS")) -- 8
-- 获取处理器CPU修订号
print(os.getenv("PROCESSOR_REVISION")) -- 3c03
-- 获取处理器CPU的型号
print(os.getenv("PROCESSOR_LEVEL")) -- 6
-- 获取处理器CPU的架构
print(os.getenv("PROCESSOR_ARCHITECTURE")) -- AMD64
-- 获取处理器CPU标识
print(os.getenv("PROCESSOR_IDENTIFIER")) -- Intel64 Family 6 Model 60 Stepping 3, GenuineIntel

-- 获取命令行解释器可执行程序的完整路径
print(os.getenv("COMSPEC")) -- C:\WINDOWS\system32\cmd.exe
print(os.getenv("ComSpec")) -- C:\WINDOWS\system32\cmd.exe
-- 获取系统支持的文件扩展名
print(os.getenv("PATHEXT")) -- .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC

-- 获取用户主目录的本地驱动器(本地盘符)
print(os.getenv("HOMEDRIVE")) -- C:
-- 获取系统根目录
print(os.getenv("SystemRoot")) -- C:\WINDOWS
-- 获取用户配置文件路径
print(os.getenv("ALLUSERSPROFILE")) -- C:\ProgramData
-- 获取用户主目录完整路径
print(os.getenv("HOMEPATH")) -- \Users\jc
-- 获取系统临时目录完整路径
print(os.getenv("TEMP")) -- C:\Users\jc\AppData\Local\Temp
print(os.getenv("ProgramFiles")) -- C:\Program Files
print(os.getenv("APPDATA")) -- C:\Users\jc\AppData\Roaming
print(os.getenv("CommonProgramFiles")) -- C:\Program Files\Common Files

os.tmpname()
返回临时文件名称,自动产生临时文件并返回文件名如/tmp/sc9k,如果要使用,必须手动打开文件,最后不使用时必须手动删除。io.tmpfile()产生的临时文件程序结束后会自动删除。

print(os.tmpname()) --\sc9k.

os.rename(oldname, newname)

更改文件或目录名,若函数调用失败则返回nil和错误信息。

os.remove(filename)

删除文件或空白目录,若函数调用失败则返回nil和错误信息。

io库

Lua I/O库用于读取和处理文件,提供两套不同风格的文件处理接口(模型),分为简单模式(和C语言一样)和完全模式。

  • 简单模式(simple model)

使用隐式的文件句柄,假设有一个当前当前输入文件和一个当前输出文件,提供默认输入文件和输出文件的操作。拥有一个当前输入文件和一个当前输出文件,提供针对这些文件相关的操作。

使用隐含的文件描述符,有操作设置默认的输入文件和输出文件。

  • 完全模式(complete model)

使用显式文件句柄,使用外部的文件句柄来实现,以面向对象的方式,将所有文件操作定义为文件句柄的方法。

明确的操作描述符

使用明确的文件描述符时,所有操作由表io提供,使之能够在同一时间内处理多个文件,功能相当相似的隐式文件操作符。

-- 使用明确的文件描述符能够在同一时间处理多个文件
file:function

-- eg
file = io.open("test.lua", "r")
print(file:read())
file:close()

file = io.open("test.lua", "a")
file:write("---------------------")
file:close()

io.open 返回文件操作符和操作方法,表io提供3个与定义的文件描述符:

  • io.stderr 标准错误输出

  • io.stdin 标准输入

  • io.stdout 标准输出

  • io表调用方式

表io中提供三个和C语言中含义相同的预定义文件句柄:io.stdinio.stdoutio.stderr。IO库永远不会关闭这些文件。

使用io表,io.open()将返回指定文件的描述,且所有的操作将围绕这个文件描述io表同样提供3中预定义的文件描述:io.stdinio.stdoutio.stderr

  • 文件句柄直接调用方式

使用file:xxx()函数方式进行操作,其中fileioi.open()返回的文件句柄,多数io函数调用失败时返回nil和错误信息。

除非另有说明,IO函数在出错时都返回nil,第二个返回值为错误消息,第三个返回值为系统相关的错误代码。成功时返回与nil不同的值。

简单模式

简单模式的所有操作都作用于两个当前文件,I/O库将当前输入文件初始化为进程标准输入stdin,将当前输出文件初始化为进程标准输出stdout

I/O库会将标准输入输出作为其缺省的输入文件和输出文件,可通过io.input(filename)io.output(filename)来改变当前输入输出文件。

使用io.write()io.read()从标准输入stdin读取输出到标准输出stdout,在执行io.read()操作时,会从标准输入中读取一行。使用io.input()io.output()改变当前文件。

io.input(filename)

以只读模式打开指定文件,并将其设定为当前输入文件,除非再次调用io.input(),否则所有的输入都将来源于这个文件。

io.input([file])

相当于io.input,但操作在默认输出文件上。使用文件名调用时,以文本模式来打开该名称的文件,并将文件句柄设置为默认输入文件。若使用文件句柄去调用它,则简单地将句柄设置为默认输入文件。若调用时不传入参数则返回当前的默认输出文件。在出错的情况下,函数抛出错误而非返回错误码。

io.output(filename)

在输出方面,io.output()也可以完成类似的工作。

io.output([file])

使用文件名称调用时,以文本模式打开该名称的文件,并将文件句柄设置为默认输出文件。若使用文件句柄去调用它,就简单地将该句柄设置为默认输出和文件。若调用时不传入参数则返回当前的默认输出文件。

io.read()

io.read(...)

# 相当于 

io.input():read

按指定的格式读取一个文件,按每个格式函数将返回一个字符串或数字,若不能正确地读取将返回nil,若没有指定格式将指默认按行方式进行读取。

读取格式

  • *a 从当前位置读取整个文件,若为文件结尾EOF则返回空字符串。
io.read("*all")

读取当前输入文件的所有内容,以当前位置作为开始。若当前位置处于文件末尾或文件为空则返回空字符串。由于Lua可以高效地处理长字符串,因此在Lua中可先将数据从文件中完整读出之后在通过字符串库提供的函数进行各种处理。

  • *l 默认选项,读取下一行的内容,若为文件结尾EOF则返回nil
io.read("*line")

-- eg
for count = 1, math.huge do
  local line = io.read("*line") -- 缺省值为 *line
  if line == nil then
    break
  end
  io.write(string.format("%6d", count), line, "\n")
end

-- 若为了迭代文件中所有行可使用 io.lines ,以迭代器的形式访问文件中的每一行数据。
local lines = {}
-- 通过迭代器访问每行数据
for line in io.lines() do
  lines[#lines+1] = line
end
-- 使用Lua标准库table进行排序
table.sort(lines)
for _,l in ipairs(lines) do
  io.write(l, "\n")
end

返回当前文件的下一行但不包含换行符,当到达文件末尾时则返回nil

  • number 读取指定字节数的字符,若为文件结尾EOF则返回nil,若number为0则返回空字符串。
io.read("*number")

-- eg:读取注释中的数字
while true do
  local n1,n2,n3 = io.read("*number", "*number", "*number")
  if not n1 then 
    break
  end
  print(math.max(n1,n2,n3))
end

从当前输入文件中读取一个数字,此时read将直接返回一个数字而非字符串。*number 选项会忽略数字前面所有的空格,且能处理像-3+5.2这样的数字格式。若当前读取的数据不合法则返回nil。调用时可指定多个选项,函数会根据每个选项参数返回相应的内容。

  • *n 读取一个数字并返回它
-- 从输入文件中最多读取n个字符,若读取不到任何字符则返回 nil,否则返回读取到的字符串。
io.read(<num>)

-- eg
while true do
  local block = io.read(2^13)
  if not block then
    break
  end
  io.write(block)
end

-- 特殊情况,用于检查是否到达文件末尾,若尚未到达则返回空字符串否则返回 nil。
io.read(0)

io.write(...)

-- 将所有参数顺序的写入到当前输出文件中
io.write(...)

-- 相当于

io.output():write

-- eg:获取任意数目的字符串参数并将其写入当前标准输出中
local t = io.write("sin(3)=", math.sin(3), "\n")
print("hello", "lua")

io.writeprint不同之处在于,io.write不附加任何额外的字符到输出中,例如制表符、换行符等。io.write是使用当前输出文件而print始终使用标准输出。print会自动调用参数的tostring方法,所以可以显示出表、函数和nil

io.open(filename [,mode])

按指定模式mode打开一个文件,成功则返回新的文件句柄,失败则返回nil和错误信息。

文件模式

  • r 默认选项,只读模式,对已存在的文件的默认打开模式。
  • w 可写模式,允许修改已存在的文件和创建新文件且不可读取。
  • a 追加模式,对于已存在的文件允许追加新内容,但不允许修改原来内容,同时也可以创建新文件。
  • r+ 更新模式,之前数据将被保存。读写模式,打开已存在的文件。
  • w+ 更新模式,之前数据将被清除。若文件已存在则删除文件中的数据,若文件不存在则创建文件,并以读写模式打开。
  • a+ 添加更新模式,之前数据将被保存,仅允许在文件末尾进行添加。以可读的追加模式打开已存在的文件,若文件不存在则新建文件。
  • b 某些系统支持二进制方式
-- 读取指定文件
function getFile(filename)
  local file = assert(io.open(filename, "r"))
  local string = file:read("*all")
  file:close()
  return string
end

-- 按行方式读取文件内容
function getFileLine(filename)
  local BUFSIZE = 84012
  local file = assert(io.open(filename, "r"))
  local lines,rest = file:read(BUFSIZE, "*line")
  file:close()
  return lines,rest
end

-- 以字符串方式写入文件
function writeFile(filename, string)
  local file = assert(io.open(filename, "w"))
  file:write(string)
  file:close()
end

-- 控制台写入字符串到文件
function writeConoleToFile(filename)
  local file = assert(io.open(filename, "w"))
  local string = io.read()
  file:write(string)
  file:close()
ene

io.popen([prog[, mode]])

开始程序prog与额外的进程,并返回用于prog的文件句柄,并不支持所有的系统平台。

使用一个分离进程开启程序program,返回的文件句柄可用于从这个程序中读取数据(mode=r)或是向程序写入输入(mode=w)。

io.close(file)

io.close([file])

# 相当于

file:close()

关闭默认的输出文件,当文件句柄被垃圾收集后,文件将自动关闭,句柄将变为一个不可预知的值。

io.tmpfile()

返回一个临时文件句柄,该文件以更新模式打开,程序结束时自动删除。

io.type(obj)

检测obj是否为一个可用的文件句柄,若obj是一个打开的文件句柄则返回字符串file,若obj是一个关闭的文件句柄则返回字符串close file。若obj不是句柄则返回nil

返回值

  • file 为一个打开的文件句柄
  • close file 为一个已关闭的文件句柄
  • nil 表示obj不是一个文件句柄

io.flush()

io.flush()
# 相当于
file:flush()

向文件写入缓冲中的所有数据,输出所有缓冲区中的内容到默认输出文件。

io.lines(optional filename)

io.lines([filename])

提供一个循环迭代器以遍历文件,若指定文件名则当遍历结束后将自动关闭该文件,若使用默认文件则遍历结束后不会自动关闭文件。

打开指定的文件filename为读模式并返回一个迭代函数,每次调用将获取文件中的一行内容,当到达文件结尾时,将返回nil并自动关闭文件。

若不带参数时,io.lines()相当于io.input():lines(),表示读取默认输入设备的内容但结束时不关闭文件。

返回一个迭代函数,每次调用将获得文件中的一行内容,当到达文件结尾时将返回nil,但不关闭文件。

for line in io.lines("main.lua") do
  print(line)
end

debug库

Lua本身并未内置调试器,提供了debug库用于提供创建自定义调试器的功能。出于性能考虑,调用基本功能的正式接口都是通过 C API提供,在Lua中访问debug库的一种方式是通过Lua代码直接访问。与其他库不同的debug库很多功能都会影响性能。其次,它打破了Lua中一些颠覆不破的真理,如在一个局部变量的作用域之外不能访问。

debug库中的一种重要的思想是栈级别(stack level),一个栈级别就是一个指向在当前时刻正在活动的特殊函数的数字。也就是说,这个函数正在被调用但还没有返回。调用debug库的函数级别为1,调用它的函数级别为2,以此类推。

Lua的调试库包含两种函数:自省函数(introspective functions)和钩子(hooks)。自省函数可用来监视一个正在运行的程序的信息,如活动函数的栈、当前的执行行、局部变量值和名称等。钩子可以跟踪程序的运行。自省函数主要是debug.getinfo

自省函数

  • debug.getinfo([thread,]func[,what]) 返回一个函数的信息表
  • debug.traceback([thread,][message[, level]]) 获取调用栈的回溯信息

debug.getinfo([thread,]func[,what])

debug.getinfo 参数

  • func 可直接传入函数,也可传入一个数值,此数值表示函数(运行在指定线程)的调用栈深度,0表示getinfo自己,1表示调用getinfo的函数,以此类推一般是2。若此数值大于活动函数的深度返回nil
  • what函数类型,若func是一个普通的Lua函数则为Lua,若func是一个C函数则为C,若是Lua主程序块(chunk)部分则为main

debug.getinfo 返回值是一个table包含以下字段

  • source函数定义的位置,若函数时通过loadstring在一个字符串中定义的,那么source就是这个字符串。若函数是在一个文件中定义的,那么source就是这个文件名加前缀@
  • short_srcsource的短版本,最多60个字符,可用于错误信息汇总。
  • linedefined 该函数定义的源代码中第一行的行号
-- 获取当前栈的追溯信息
function traceback()
    -- 获取相应栈层上函数的信息
    for level=1,math.huge do
        -- 获取函数信息
        -- S 选择 
        --      source 函数定义的位置
        --      short_src 函数定义位置的短版本,最多60个字符。
        --      what 函数的类型
        --      linedefined 函数定义在源代码中第一行的行号
        --      lastlinedefined 函数定义在源代码中最后一行的行号
        -- l 选择 
        --      currentline 当前所在行
        local info = debug.getinfo(level, "Sl")
        -- 判断是否具有上层函数
        if not info then
            break
        end
        -- 判断是否为一个C函数
        if info.what=="C" then
            print(level, "C function")
        else
            print(string.format("file:%s line:%d", info.short_src, info.currentline))
        end
    end
end
traceback()
--[[
file:D:\lua\test\test.lua line:6
file:D:\lua\test\test.lua line:19
3   C function
--]]

debug.traceback([thread,][message[, level]])

获取调用栈的回溯信息

debug.traceback参数

  • message 字符串 可选项 被添加在栈回溯信息的开头。
  • level 数值 可选项 指明从栈的哪一层开始回溯,默认为1即调用traceback的位置。

若有message值且不是字符串或niltraceback函数不做任何处理直接返回message,否则返回调用栈的回溯信息。

自定义的调试器

function __G__TRACKBACK__(errmsg)
  print("LUA ERROR: "..tostring(errmsg).."\n")
  print(debug.traceback("", 2))
end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容