1. 程式人生 > >[Lua]Lua IO庫整理

[Lua]Lua IO庫整理

I/O庫為檔案操作提供了兩種不同的模型,簡單模型和完整模型。簡單模型假設有一個當前輸入檔案和一個當前輸出檔案,它的I/O操作均作用於這些檔案完整模型則使用顯式地檔案控制代碼。它採用了面向物件的風格,並將所有的操作定義為檔案控制代碼上的方法。

簡單IO模式

簡單模型的所有操作都作用於兩個當前檔案。I/O庫將當前輸入檔案初始化為程序標準輸入(stdin),將當前輸出檔案初始化為程序標準輸出。在執行io.read()操作時,就會從標準輸入中讀取一行。

用函式io.inputio.output可以改變這兩個當前檔案。io.input(filename)呼叫會以只讀模式開啟指定的檔案,並將其設定為當前輸入檔案;除非再次呼叫

io.input,否則所有的輸入都將來源於這個檔案;在輸出方面,io.output也可以完成類似的工作

 io.write, io.read 是一對.預設情況下,他們從stdin讀輸入,輸出到stdout 另有兩個函式可以改變這一預設行為: io.input("xx"), io.output("yy") 他們改變輸入為某個 xx 檔案, 輸出到 yy 檔案。 eg:

如果 io.read()引數

"*all"

從當前位置讀取整個檔案,若為檔案尾,則返回空字串

"*line"

[預設]讀取下一行的內容,若為檔案尾,則返回nil

"*number"

讀取指定位元組數的字元,如果number0則返回空字串,若為檔案尾,則返回

nil;

<num>

讀取num個字元到串

--[[test.lua的內容
hello world,I is test.lua
print(123)
--]]
 io.input("E:\\workplace\\project\\server\\script\\test\\src\\test.lua")
 t=io.read("*all")
 io.write(t, '\n')  ------輸出整個 test.lua 檔案的內容到 stdin
--> --hello world,I is test.lua
--> print(123)

函式名

功能描述

io.close([file])

相當於file:close(),關閉預設的輸出檔案

io.flush()

相當於file:flush(),輸出所有緩衝中的內容到預設輸出檔案

io.lines ([filename])

開啟指定的檔案filename為讀模式並返回一個迭代函式,每次呼叫將獲得檔案中的一行內容,當到檔案尾時,將返回nil,並自動關閉檔案
若不帶引數時io.lines() <=> io.input():lines(); 讀取預設輸入裝置的內容,但結束時不關閉檔案
如:for line in io.lines("main.lua") do
print(line)
end

io.input ([file])

io.output ([file])

相當於io.input,但操作在預設輸出檔案上

io.read (...)

相當於io.input():read

io.write (...)

相當於io.output():write

io.tmpfile ()

返回一個臨時檔案控制代碼,該檔案以更新模式開啟,程式結束時自動刪除

io.type (obj)

檢測obj是否一個可用的檔案控制代碼;返回:
"file":為一個開啟的檔案控制代碼
"closed file":為一個已關閉的檔案控制代碼
nil:表示obj不是一個檔案控制代碼

--print與io.write的不同
--Write函式與print函式不同在於,write不附加任何額外的字元到輸出中去,例如製表符,換行符等等。還有write函式是使用當前輸出檔案,而print始終使用標準輸出。另外print函式會自動呼叫引數的tostring方法,所以可以顯示出表(tables)函式(functions)和nil。
print("hello", "Lua"); 
print("Hi")
--> hello   Lua
--> Hi
io.write("hello", "Lua"); 
io.write("Hi", "\n")
--> helloLuaHi
-- Opens a file in read
local file = io.open("E:\\workplace\\project\\server\\script\\test\\src\\test.lua", "r")
io.input(file)--設定當前檔案為預設輸出檔案
print(io.read())--預設讀取第一行 
--> --hello world,I is test.lua
io.close(file)--關閉

-- Opens a file in append mode
file = io.open("E:\\workplace\\project\\server\\script\\test\\src\\test.lua", "a")
-- sets the default output file as test.lua
io.output(file)
-- appends a word test to the last line of the file
io.write("-- End of the test.lua file\n")
-- closes the open file
io.close(file)

--[[操作前
--hello world,I is test.lua
print(123)
--]]
--[[操作後
--hello world,I is test.lua
print(123)-- End of the test.lua file
--]]

完全IO模式

簡單I/O功能太受限了,以至於基本沒有什麼用處,而用的更多的則是這裡說的完整I/O模型。完整I/O模型可以進行更多的I/O控制,它是基於檔案控制代碼的,就好比與C語言中的FILE*,表示一個正在操作的檔案。

要開啟一個檔案,可以使用io.open函式,它有兩個引數,一個表示要開啟的檔名,另一個表示操作的模式字串。模式字串可以有以下四種取值方式:io.open(filename,[mode])mode取值

"r"

是隻讀方式開啟(預設), 不能寫入。

"w"

只寫方式開啟,不能讀取。

"a"

追加開啟一個現有的檔案或進行追加建立一個新的檔案模式。

"r+"

以讀寫方式開啟,保留原有資料。這個模式是自由度最高的。

"w+"

以讀寫方式開啟,刪除原有資料。就是開啟後文件是空檔案。

"a+"

以讀寫方式開啟,保留原有資料,只能在檔案末尾新增,不能在檔案中間改寫資料。若找不到檔案,也會建立新檔案

"b"

某些系統支援二進位制方式

正常情況下open函式返回一個檔案的控制代碼。如果發生錯誤,則返回nil,以及一個錯誤資訊和錯誤程式碼。  

當成功開啟一個檔案以後,就可以使用read/write方法讀寫檔案了,這與read/write函式相似,但是需要用冒號語法,將它們作為檔案控制代碼的方法來呼叫

函式名

功能描述

io.open (filename [, mode])

按指定的模式開啟一個檔案,成功則返回檔案控制代碼,失敗則返回nil+錯誤資訊

file:close()

關閉檔案
注:當檔案控制代碼被垃圾收集後,檔案將自動關閉。控制代碼將變為一個不可預知的值

file:flush()

向檔案寫入緩衝中的所有資料

file:lines()

返回一個迭代函式,每次呼叫將獲得檔案中的一行內容,當到檔案尾時,將返回nil,但不關閉檔案

如:for line in file:lines() do body end

file:read(...)

按指定的格式讀取一個檔案,按每個格式函式將返回一個字串或數字,如果不能正確讀取將返回nil,若沒有指定格式將指預設按行方式進行讀取

file:write(...)

按指定的引數格式輸出檔案內容,引數必須為字元或數字,若要輸出其它值,則需通過tostringstring.format進行轉換

file:seek([whence][,offset])

置和獲取當前檔案位置,成功則返回最終的檔案位置(按位元組),失敗則返回nil加錯誤資訊whence:
"set": 從檔案頭開始
"cur": 從當前位置開始[預設]
"end": 從檔案尾開始
offset:預設為0
不帶引數file:seek()則返回當前位置,file:seek("set")則定位到檔案頭,file:seek("end")則定位到檔案尾並返回檔案大小

file:setvbuf(mode,[,size])

設定輸出檔案的緩衝模式mode:
"no": 沒有緩衝,即直接輸出
"full": 全緩衝,即當緩衝滿後才進行輸出操作(也可呼叫flush馬上輸出)
"line": 以行為單位,進行輸出(多用於終端裝置)
最後兩種模式,size可以指定緩衝的大小(按位元組),忽略size將自動調整為最佳的大小

-- Opens a file in read mode
file = io.open("E:\\workplace\\project\\server\\script\\test\\src\\test.lua", "r")
-- prints the first line of the file
print(file:read())
--> --hello world,I is test.lua
-- closes the opened file
file:close()

-- Opens a file in append mode
file = io.open("E:\\workplace\\project\\server\\script\\test\\src\\test.lua", "a")
-- appends a word test to the last line of the file
file:write("--test\n")
-- closes the open file
file:close()

--[[操作前
--hello world,I is test.lua
print(123)-- End of the test.lua file
--]]
--[[操作後
--hello world,I is test.lua
print(123)-- End of the test.lua file
--test
--]]

Lua IO庫擴充套件

--------------------------------
-- @module io

-- start --

--------------------------------
-- 檢查指定的檔案或目錄是否存在,如果存在返回 true,否則返回 false
-- @function [parent=#io] exists
-- @param string path 要檢查的檔案或目錄的完全路徑
-- @return boolean#boolean 

--[[--

檢查指定的檔案或目錄是否存在,如果存在返回 true,否則返回 false

可以使用 cc.FileUtils:fullPathForFilename() 函式查詢特定檔案的完整路徑,例如:

~~~ lua

local path = cc.FileUtils:getInstance():fullPathForFilename("gamedata.txt")
if io.exists(path) then
    ....
end

~~~

]]

-- end --

function io.exists(path)
    local file = io.open(path, "r")
    if file then
        io.close(file)
        return true
    end
    return false
end

-- start --

--------------------------------
-- 讀取檔案內容,返回包含檔案內容的字串,如果失敗返回 nil
-- @function [parent=#io] readfile
-- @param string path 檔案完全路徑
-- @return string#string 

--[[--

讀取檔案內容,返回包含檔案內容的字串,如果失敗返回 nil

io.readfile() 會一次性讀取整個檔案的內容,並返回一個字串,因此該函式不適宜讀取太大的檔案。

]]

-- end --

function io.readfile(path)
    local file = io.open(path, "r")
    if file then
        local content = file:read("*a")
        io.close(file)
        return content
    end
    return nil
end

-- start --

--------------------------------
-- 以字串內容寫入檔案,成功返回 true,失敗返回 false
-- @function [parent=#io] writefile
-- @param string path 檔案完全路徑
-- @param string content 要寫入的內容
-- @param string mode 寫入模式,預設值為 "w+b"
-- @return boolean#boolean 

--[[--

以字串內容寫入檔案,成功返回 true,失敗返回 false

"mode 寫入模式" 引數決定 io.writefile() 如何寫入內容,可用的值如下:

-   "w+" : 覆蓋檔案已有內容,如果檔案不存在則建立新檔案
-   "a+" : 追加內容到檔案尾部,如果檔案不存在則建立檔案

此外,還可以在 "寫入模式" 引數最後追加字元 "b" ,表示以二進位制方式寫入資料,這樣可以避免內容寫入不完整。

**Android 特別提示:** 在 Android 平臺上,檔案只能寫入儲存卡所在路徑,assets 和 data 等目錄都是無法寫入的。

]]

-- end --

function io.writefile(path, content, mode)
    mode = mode or "w+b"
    local file = io.open(path, mode)
    if file then
        if file:write(content) == nil then return false end
        io.close(file)
        return true
    else
        return false
    end
end

-- start --

--------------------------------
-- 拆分一個路徑字串,返回組成路徑的各個部分
-- @function [parent=#io] pathinfo
-- @param string path 要分拆的路徑字串
-- @return table#table 

--[[--

拆分一個路徑字串,返回組成路徑的各個部分

~~~ lua

local pathinfo  = io.pathinfo("/var/app/test/abc.png")

-- 結果:
-- pathinfo.dirname  = "/var/app/test/"
-- pathinfo.filename = "abc.png"
-- pathinfo.basename = "abc"
-- pathinfo.extname  = ".png"

~~~

]]

-- end --

function io.pathinfo(path)
    local pos = string.len(path)
    local extpos = pos + 1
    while pos > 0 do
        local b = string.byte(path, pos)
        if b == 46 then -- 46 = char "."
            extpos = pos
        elseif b == 47 then -- 47 = char "/"
            break
        end
        pos = pos - 1
    end

    local dirname = string.sub(path, 1, pos)
    local filename = string.sub(path, pos + 1)
    extpos = extpos - pos
    local basename = string.sub(filename, 1, extpos - 1)
    local extname = string.sub(filename, extpos)
    return {
        dirname = dirname,
        filename = filename,
        basename = basename,
        extname = extname
    }
end

-- start --

--------------------------------
-- 返回指定檔案的大小,如果失敗返回 false
-- @function [parent=#io] filesize
-- @param string path 檔案完全路徑
-- @return integer#integer 

-- end --

function io.filesize(path)
    local size = false
    local file = io.open(path, "r")
    if file then
        local current = file:seek()
        size = file:seek("end")
        file:seek("set", current)
        io.close(file)
    end
    return size
end
這些quick_cocos中的