1. 程式人生 > >高速掌握Lua 5.3 —— I/O庫 (1)

高速掌握Lua 5.3 —— I/O庫 (1)

跳過 控制 ont haml end {} simple table 最大

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

高速掌握Lua 5.3 —— I/O庫 (1)