快速掌握Lua 5.3 —— I/O库 (1)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/VermillionTear/article/details/50758857

Q:什么是”Simple Model”?

A:所有的文件操作都基于一个默认的输入文件和一个默认的输出文件,这就意味着同一时间对于输入和输出来说,只可操作一个文件(默认的文件)。默认的输入文件初始化是stdin,默认的输出文件初始化是stdout

-- "a.lua"文件中:
--[[ "io.read()"从"io.input()"所指定的默认输入文件中读;
     "io.write()"向"io.output()"所指定的默认输出文件中写。
     因为默认输入文件初始化是"stdin";默认的输出文件初始化是"stdout",
     所以"io.read()"从"stdin"读;"io.write()"向"stdout"写。]]
io.write(io.read())
--[[ result: 
     > lua a.lua
     Hello World!
     Hello World!]]

io.read()io.write()都可以接收多个参数,

-- "a.lua"文件中:
io.write(io.read(), " and", " The Complete I/O Model.")
--[[ result: 
     > lua a.lua
     The Simple I/O Model
     The Simple I/O Model and The Complete I/O Model.]]

io.input()io.output()可以更改对应的默认文件,

-- "file1.txt"文件中:
Hello World!
-- "a.lua"文件中:
local temp_input = io.input()    -- 保存原先的默认输入文件(此时是"stdin")。
local temp_output = io.output()    -- 保存原先的默认输出文件(此时是"stdout")。
io.input("file1.txt")    -- 指定默认的输入文件为"file1.txt"。
io.output("file2.txt")    -- 指定默认的输出文件为"file2.txt"。
io.write(io.read())
io.input():close()    -- 关闭"file1.txt"。
io.output():close()    -- 关闭"file2.txt"。
io.input(temp_input)    -- 恢复原先的默认输入文件。
io.output(temp_output)    -- 恢复原先的默认输出文件。
--[[ result: 
     > lua a.lua
     > cat file2.txt
     Hello World!]]

Q:print()io.write()有什么区别?

A:
1、print()在打印其每个参数之间增加\t,且最后增加\n,而io.write()均不会。

print("hello", "Lua")
print("Hi")
--[[ result: 
     hello    Lua
     Hi]]
io.write("hello", "Lua")
io.write("Hi", "\n")
--> helloLuaHi

2、io.write()io.output()指定的文件中写(初始值是stdout),而print()总向stdout写。

-- "a.lua"文件中:
local temp = io.output()
io.output("file3.txt")
io.write("Hello")
print(" World")
io.output():close()
io.output(temp)
--[[ result: 
     "file3.txt"文件中:
     Hello
     "stdout":
      World]]

3、print()对于不能被直接打印的对象会自动调用tostring()转换,而io.write()不会。

t = {}
print(t)    --> table: 0x1ca9aa0
io.write(t)    --> error

Q:io.read()的参数?

A:

-- "file1.txt"文件中:
line1
line2
line3

-- "data.txt"文件中:
6.0       -3.23     15e12
4.3       234       1000001

1、*a从当前的文件读取位置读取到文件尾,如果文件为空或者已在文件尾,则返回空串,

local temp = io.input()
io.input("file1.txt")
io.write(io.read("*a"))
io.input():close()
io.input(temp)
--[[ result: 
     line1
     line2
     line3]]

2、*l从当前的文件读取位置读取到行尾,不包含结尾的\n*L*l功能相同,但包含行尾的\n。如果文件为空或者已在文件尾,则返回nil

local temp = io.input()
io.input("file1.txt")
str = ""
local i = 1
while true do
    local s
    if i == 2 then 
        s = io.read("*L")
    else
        s = io.read("*l")    -- "io.read()"不指定参数时,默认使用"*l"参数。
    end
    if s == nil then break end    -- 当文件读取完时,返回"nil"。
    str = str .. s
    i = i + 1
end
io.write(str)
--[[ result: 
     line1line2
     line3]]
io.input():close()
io.input(temp)

3、*n从当前的文件读取位置读取一个数值。io.read("*n")返回数值,而不是字符串。当需要从一个文件中读取大量数字时,数字间的字符串为空格可以显著提高执行性能。io.read("*n")会跳过两个可被识别数字之间的任意空格,如果在当前位置找不到一个数字(由于格式不对,或者是到了文件的结尾),则返回nil

-- 打印文件每一行中最大的数字。
local temp = io.input()
io.input("data.txt")
while true do
    local n1, n2, n3 = io.read("*n", "*n", "*n")
    if not n1 then break end
    print(math.max(n1, n2, n3))
end
io.input():close()
io.input(temp)
--[[ result: 
     15000000000000.0
     1000001]]

4、io.read(num)可以指定一个数字,lua将尽可能读取”num”个字符(如果不够则能读多少读多少),如果文件为空或者已读取到文件尾则返回nil

local temp = io.input()
io.input("data.txt")
io.write(io.read(3))    -- 读取3个字符。
print()
-- 读取100个字符。但实际没有那么多,所以能读取多少读多少。
io.write(io.read(100))
io.input():close()
io.input(temp)
--[[ result: 
     6.0
            -3.23     15e12
     4.3       234       1000001]]

Q:其他的”Simple Model”模式的库函数?

A:

--[[ io.tmpfile()
     以"w+"的模式打开一个临时文件,并返回其文件句柄。
     当程序运行结束时,该文件会被自动删除。]]
local f = io.tmpfile()
f:write("123")
f:seek("set", 0)    -- 将文件的当前读取位置定位到文件头。
print(f:read())    -- 123
f:close()

--[[ io.type(obj)
     检查"obj"是否为有效的文件句柄。函数返回如下:
     "file": 如果"obj"是一个被打开的文件句柄。
     "closed file": 如果"obj"是一个被关闭的文件句柄。
     nil: 如果"obj"不是一个有效的文件句柄。]]
print(io.type(f))    -- nil
f = io.tmpfile()
print(io.type(f))    -- file
f:close()
print(io.type(f))    -- closed file

附加:

1、io.input()io.output()在出错时均会报错。如果想控制错误,请使用”Complete model”下的io.open()
2、向io.write()传递的数字参数会被自动转换为字符串。如果想完全控制转换,最好使用string.format()

io.write("sin(3) = ", math.sin(3), "\n")
--> sin(3) = 0.14112000805987
io.write(string.format("sin(3) = %.4f\n", math.sin(3)))
--> sin(3) = 0.1411

3、避免写io.write(a..b..c)这样的代码,io.write(a, b, c)能够完成相同的工作,同时避免了..操作符复制字符串所耗费的内存资源。
4、当文件为空,或者文件当前的读取位置在文件尾时,io.read("*a")会返回空字符串,而io.read("*l")io.read("*L")io.read("*n")io.read(num)都会返回nil
5、如果想要逐行的读取文件,相比io.read("*l"),更好的选择是io.lines()io.lines()可以指定想要读取的文件,并且可以指定多个,依次的按行读取这些文件。同时在读取完毕后,io.lines()会自动关闭文件。

-- 为文件的每一行增加行号。
-- "file1.txt"文件中。
line1
line2
line3
-- "a.lua"文件中。
local count = 1
for line in io.lines("file1.txt") do
    io.write(string.format("%6d ", count), line, "\n")
    count = count + 1
end
--[[ result: 
     > lua a.lua
          1 line1
          2 line2
          3 line3]]

然而如果io.lines()不带参数,则与io.read()的功能相同,同时在读取完毕后不会关闭文件。
6、如果对于文件需要逐块的操作,但最终会操作整个文件。那么最好使用io.read("*a")读取整个文件,然后使用string.gmatch()分解出需要操作的块,

-- 上面打印文件每一行中最大的数字的例子。
-- 需要处理的块,一个或多个非空格加上一个或多个空格……
local block = "(%S+)%s+(%S+)%s+(%S+)%s+"
--[[ "string.gmatch()"返回的结果是字符串形式的,
     如果直接传递给"math.max()"会按照字符串形式比较大小,
     所以需要使用"tonumber()"转换为数字。]]
for n1, n2, n3 in string.gmatch(io.read("*a"), block) do
    print(math.max(tonumber(n1), tonumber(n2), tonumber(n3)))
end

省去了多次读文件的操作,效率会更高。
7、在Lua中拷贝文件的高效的方式,

local size = 2^13    -- good buffer size (8K)
while true do
    local block = io.read(size)
    if not block then break end
    io.write(block)
end

8、io.read(0)测试是否到了文件尾。如果未到,则返回空字符串,如果到了则返回nil

猜你喜欢

转载自blog.csdn.net/VermillionTear/article/details/50758857
5.3