Lua - io.open()仅支持最多2GB?

我正在使用 Lua 脚本来确定文件大小:

local filesize=0
local filePath = "somepath.bin"
local file,msg = io.open(filePath, "r")
if file then
    filesize=file:seek("end")
    file:close()
    filePresent = true
end

然而,这似乎只适用于文件大小不超过 2GB。对于较大的文件,filesize 总是 nil。是否存在对 io.open 的限制?如果有,我该如何解决?

在 Windows Server 2008 R2 64 位上运行 Lua 5.1.4。

点赞
用户3677376
用户3677376

在内部,Lua使用ISO C函数long int ftell(FILE * stream);来确定file:seek()的返回值。在Windows上,long int始终是32位,因此您在此处没有运气。如果可以的话,您应该使用一些外部库来检测文件大小 - 我建议使用[luafilesystem](http://keplerproject.github.io/luafilesystem/)。

2014-11-05 10:33:12
用户1009479
用户1009479

问题不在于 io.open,而在于 file:seek。你可以像这样检查错误:

filesize, err = file:seek("end")
if not filesize then
    print(err)
end

错误信息可能是 Invalid argument。这是因为对于大于2GB的文件,其大小超过了32位 long 可以容纳的范围,导致 C 函数 fseek 无法工作。

在 POSIX 系统中,Lua 使用了 fseeko,其使用 off_t 的大小而不是 fseek 中的 long。在 Windows 中,则有 _fseeki64,我猜它的作用类似。如果这些不可用,就会使用 fseek,并且会导致问题出现。


相关源代码在 liolib.c(Lua 5.2)中。正如 @lhf 指出的那样,在 Lua 5.1 中,始终使用 fseeksource)。升级到 Lua 5.2 可能可以解决问题。

2014-11-05 10:48:51
用户1847592
用户1847592

在旧版的 Lua 中(其中 file:seek() 受到 2Gb 的限制),你可以请求 cmd.exe 来获取文件大小:

function filesize(filename)
   -- 返回文件大小(如果文件不存在或无法打开,则返回 nil)
   local command = 'cmd /d/c for %f in ("'..filename..'") do @echo(%~zf'
   return tonumber(io.popen(command):read'*a')
end

print(filesize[[C:\Program Files\Windows Media Player\wmplayer.exe]])
         --> 73728
print(filesize[[E:\City.of.the.Living.Dead.1980.720p.BluRay.x264.Skazhutin.mkv]])
         --> 8505168882
2016-04-21 10:08:39