先简单介绍一下被迫使用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

Lua的文件操作的更多相关文章

  1. lua向文件中写入数据,进行记录

    function readfile(path) local file = io.open(path, "r") if file then local content = file: ...

  2. 【.NET深呼吸】Zip文件操作(1):创建和读取zip文档

    .net的IO操作支持对zip文件的创建.读写和更新.使用起来也比较简单,.net的一向作风,东西都准备好了,至于如何使用,请看着办. 要对zip文件进行操作,主要用到以下三个类: 1.ZipFile ...

  3. 野路子出身PowerShell 文件操作实用功能

    本文出处:http://www.cnblogs.com/wy123/p/6129498.html 因工作需要,处理一批文件,本想写C#来处理的,后来想想这个是PowerShell的天职,索性就网上各种 ...

  4. Node基础篇(文件操作)

    文件操作 相关模块 Node内核提供了很多与文件操作相关的模块,每个模块都提供了一些最基本的操作API,在NPM中也有社区提供的功能包 fs: 基础的文件操作 API path: 提供和路径相关的操作 ...

  5. 归档NSKeyedArchiver解归档NSKeyedUnarchiver与文件管理类NSFileManager (文件操作)

    ========================== 文件操作 ========================== 一.归档NSKeyedArchiver 1.第一种方式:存储一种数据. // 归档 ...

  6. SQL Server附加数据库报错:无法打开物理文件,操作系统错误5

    问题描述:      附加数据时,提示无法打开物理文件,操作系统错误5.如下图: 问题原因:可能是文件访问权限方面的问题. 解决方案:找到数据库的mdf和ldf文件,赋予权限即可.如下图: 找到mdf ...

  7. 通过cmd完成FTP上传文件操作

    一直使用 FileZilla 这个工具进行相关的 FTP 操作,而在某一次版本升级之后,发现不太好用了,连接老是掉,再后来完全连接不上去. 改用了一段时间的 Web 版的 FTP 工具,后来那个页面也 ...

  8. Linux文件操作的主要接口API及相关细节

    操作系统API: 1.API是一些函数,这些函数是由linux系统提供支持的,由应用层程序来使用,应用层程序通过调用API来调用操作系统中的各种功能,来干活 文件操作的一般步骤: 1.在linux系统 ...

  9. C语言的fopen函数(文件操作/读写)

    头文件:#include <stdio.h> fopen()是一个常用的函数,用来以指定的方式打开文件,其原型为:    FILE * fopen(const char * path, c ...

随机推荐

  1. 【Java】 大话数据结构(8) 串的模式匹配算法(朴素、KMP、改进算法)

    本文根据<大话数据结构>一书,实现了Java版的串的朴素模式匹配算法.KMP模式匹配算法.KMP模式匹配算法的改进算法. 1.朴素的模式匹配算法 为主串和子串分别定义指针i,j. (1)当 ...

  2. 003.FTP客户端连接

    一 命令行连接 注意: 1:命令行连接不支持目录下载,使用mget也只会将目录下文件下载,不会下载目录本身. 2:命令行连接不支持断点续传. ftp [服务端IP] -help #获取帮助 - -mg ...

  3. android 对称加密,非对称加密 android 常见的加密

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha android 常见的加密 ======== 不可逆加密:md5,sha1 可逆的加密中 ...

  4. Jindent——让intellij idea 像eclipse一样生成模版化的javadoc注释

    插件地址 http://plugins.jetbrains.com/plugin/2170?pr=idea 安装方法参考 http://www.cnblogs.com/nova-/p/3535636. ...

  5. GDI 泄漏检测方法

    方法一 1.打开电脑的[任务管理器],选择[进程]页,点击菜单项的[查看]项,选择[选择列]: 2.勾选[GDI对象(J)]即可. 3.此时,用户就可以在进程中看到每个进程对应的GDI对象,每个进程的 ...

  6. 国外IOS UI指南

    国外IOS UI指南 众所周知,IOS的界面设计,越来越流行,可以说都形成了一个标准,搜集了一些资料,供自己以后学习使用! iOS Human Interface Guidelines (中文翻译) ...

  7. LPC1800 and LPC4300 MCUs

    LPC1800 Series microcontrollers At 180 MHz, LPC1800 Series microcontrollers combine the industry's f ...

  8. [Go] Cookie 使用简介

    Golang 的 Cookie web 开发免不了要和 cookie 打交道.Go 的 http 库也提供了 cookie 的相关操作. type Cookie struct { Name strin ...

  9. Nginx FastCGI的运行原理

    http://www.cnblogs.com/yinshoucheng-golden/p/6474034.html

  10. Java嵌入式数据库H2学习总结(二)——在Web应用程序中使用H2数据库

    一.搭建测试环境和项目 1.1.搭建JavaWeb测试项目 创建一个[H2DBTest]JavaWeb项目,找到H2数据库的jar文件,如下图所示: H2数据库就一个jar文件,这个Jar文件里面包含 ...