先簡單介紹一下被迫使用Lua的IO的情境:html
遊戲支持玩家自定義上傳頭像,在排行榜中會顯示玩家列表(包括本服、跨服),原有的作法是先檢測CCUserDefault中是否存在指定圖片的key以及它的狀態。而後在下載頭像、下載完成後設置對應的狀態。這樣致使的一個問題就是CCUserDefault的讀寫徹底失效了。整個遊戲下載的補丁包判斷和其它判斷就徹底失效了,不得卸載遊戲後重裝。我的目前的推測是因爲多線程引發的,暫時沒有有效的依據node
下載頭像使用的是libcurl,嗯,又是它,在作項目這麼久的過程當中,發現它其實有不少地方比較坑。其中有一點我一直沒搞明白,一樣的同樣地址,系統自帶的瀏覽器(IOS、Android均支持)就能正常返回,而遊戲中使用libcurl去下載就是死活返回errcode 28 (CURLE_OPERATION_TIMEDOUT),libcurl我設置的是60秒超時,絕對足夠了瀏覽器
以後我作了優化,在設置自定義頭像的時候,先檢測本地是否有該文件,若是有直接就設置了,若是沒有就放置在加載隊列中,等下載完成後再設置頭像,只開一條線程去下載圖片。(同一張頭像的url只請求一次,也避免對CCUserDefault的讀寫操做)。多線程
經過libcurl下載一個「頭像id.jpg.partial」的文件,而後下載完成從新寫一個「頭像id.jpg」的文件。在下載完成的時候,只作了簡單的一個文件大小判斷,若是文件小於300B就認爲它是有問題的,直接刪除相應的文件app
-- filePath爲當前下載完成的臨時頭像文件路徑
local targetIconUrl = string.gsub(filePath, ".partial", "")
local inpFile = io.open(filePath, "rb")
local outFile = io.open(targetIconUrl, "wb")
if inpFile ~= nil then
-- 最大8KB的內存
local buffSize = 2^13
while true do
local bytes = inpFile:read(buffSize)
if not bytes then
break
end
outFile:write(bytes)
end
inpFile:close()
end
-- 獲取下載icon的大小
if outFile ~= nil then
local current = outFile:seek()
local fileSize = outFile:seek("end")
outFile:seek("set", current)
cclog("==> targetIconUrl : "..tostring(targetIconUrl)..", fileSize : "..tostring(fileSize))
outFile:close()
-- 小於300字節均認爲不正常的數據
if fileSize < 300 then
FileUtil:DeleteFile_(filePath)
FileUtil:DeleteFile_(targetIconUrl)
self:DownloadNextIconHandler()
do return end
end
end
原本,直接調用對應的FileUtil中的FileRename方法就能夠實現文件的重命名,可是線上的版本沒有導出相應的方法,致使目前只能經過Lua的IO來實現。curl
最近再看lua的源碼時,才真正意識到luaconf.h中定義的 LUAI_MAXCSTACK 是 cclosure的upvalue上限,而lua內存上限彷佛沒有找到明確的代碼。
優化
而file:read調用的是liolib.c編碼
底層經過調用fread方法來得到文件的內容,默認每次最多讀取512(LUAL_BUFFERSIZE的值)lua
而後調用file:seek(「end」)來獲取文件大小url
底層調用feek方法來實現
本覺得到這裏就結束了,實際上我遇到另一個問題。若是頭像因審覈問題被刪除了,致使404,結果底層libcurl方法沒有判斷http status code,直接判斷CURLcode的值是否爲CURLE_OK,致使將獲得的文件直接寫入了。但我從崩潰的日誌上獲得的信息是,小米4這臺設備上得到的文件大小爲18378
以後就直接報
invalid address or address of corrupt block 0x7c0eaa40 passed to dlfree
以後我修改了libcurl下載文件的代碼,但要等下次打整包的時候才能用上
把不是jpeg的圖片直接對CCSprite進行路徑賦值的時候就over了,因此須要一個檢測文件是否爲jpeg的方法
-- 判斷資源是否爲jpg
function PCUtils:CheckIsJpeg(filePath)
local isJpeg = false
if FileUtil:CheckFileExistWithFullPath(filePath) then
local inpFile = io.open(filePath, "rb")
-- 讀取前三位
local bytes = inpFile:read(3)
if bytes then
local fileHeadIden = ""
for _, b in ipairs{string.byte(bytes, 1, -1)} do
local val = string.format("%02X", b)
fileHeadIden = fileHeadIden..val
end
if string.upper(fileHeadIden) == "FFD8FF" then
isJpeg = true
else
cclog("==> filePath : "..tostring(filePath)..", fileHeadIden : "..tostring(fileHeadIden))
end
end
inpFile:close()
end
return isJpeg
end
讀取文件的前三位,轉換爲16進制,而後對比JPEG的頭部,判斷是否爲JPEG格式的文件,這個是我想起本身以前寫過的一篇文章《node.js獲取圖片文件的真實類型》
文件一些方法和代碼,好比爲什麼是r + b,以及2^13(8KB內存)這種技巧,都是參考《Lua程序設計 第二版》第21章 I/O庫,網上應該有中文版的PDF下載,自行搜索吧…
本文參考: