• Lua的文件操作


    先简单介绍一下被迫使用Lua的IO的情境:

    游戏支持玩家自定义上传头像,在排行榜中会显示玩家列表(包括本服、跨服),原有的做法是先检测CCUserDefault中是否存在指定图片的key以及它的状态。然后在下载头像、下载完成后设置对应的状态。这样导致的一个问题就是CCUserDefault的读写完全失效了。整个游戏下载的补丁包判断和其它判断就完全失效了,不得卸载游戏后重装。个人目前的推测是由于多线程引起的,暂时没有有效的依据

    下载头像使用的是libcurl,嗯,又是它,在做项目这么久的过程中,发现它其实有很多地方比较坑。其中有一点我一直没搞明白,同样的一样地址,系统自带的浏览器(IOS、Android均支持)就能正常返回,而游戏中使用libcurl去下载就是死活返回errcode 28 (CURLE_OPERATION_TIMEDOUT),libcurl我设置的是60秒超时,绝对足够了

     

    之后我做了优化,在设置自定义头像的时候,先检测本地是否有该文件,如果有直接就设置了,如果没有就放置在加载队列中,等下载完成后再设置头像,只开一条线程去下载图片。(同一张头像的url只请求一次,也避免对CCUserDefault的读写操作)。

     

    通过libcurl下载一个“头像id.jpg.partial”的文件,然后下载完成重新写一个“头像id.jpg”的文件。在下载完成的时候,只做了简单的一个文件大小判断,如果文件小于300B就认为它是有问题的,直接删除相应的文件

    -- 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来实现。

    最近再看lua的源码时,才真正意识到luaconf.h中定义的 LUAI_MAXCSTACK 是 cclosure的upvalue上限,而lua内存上限似乎没有找到明确的代码。

    而file:read调用的是liolib.c

     

    底层通过调用fread方法来获得文件的内容,默认每次最多读取512(LUAL_BUFFERSIZE的值)

     

    然后调用file:seek(“end”)来获取文件大小

    底层调用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下载,自行搜索吧…

     

    本文参考:

    lua cclosure 的 upvalue 数量限制

    Lua编码的那些陷阱

    Lua2.4 内存分配 mem.c

  • 相关阅读:
    Django Cookie Session和自定义分页
    ORM版学员管理系统3
    ORM版学员管理系统2
    ORM版学员管理系统1
    Django 基础 ORM系统
    Django 基础 模板系统
    Django 基础 视图系统
    property 与 attribute 的区别?
    SQL数据库相关
    观察者模式-猫叫了,老鼠跑了,主人醒了...
  • 原文地址:https://www.cnblogs.com/meteoric_cry/p/4668857.html
Copyright © 2020-2023  润新知