在Lua中,我应该如何将文件读取到一个字节数组中?

将一个文件读入字节数组 a,我一直在使用以下代码:

file = io.open(fileName, "rb")
str = file:read("*a")
a = {str:byte(1, #str)}

尽管它适用于较小的文件,但是对于一个 1MB 的文件,str:byte 会失败,导致 stack overflow (string slice too long)

是否有替代方法可以成功地读取这些较大的文件?

点赞
用户2303714
用户2303714

以下代码将从文件 file.txt 中读取每个 block(1 个字节)并将其存储到 bytes 表中。

local bytes = {}
file = assert(io.open("file.txt","rb"))
block = 1 -- 每次读取 1 个字节
while true do
    local byte = file:read(block)
    if byte == nil then
        break
    else
        bytes[#bytes+1] = string.byte(byte)
    end
end
file:close()
2013-05-12 11:18:54
用户1847592
用户1847592
local fileName = 'C:\\Program Files\\Microsoft Office\\Office12\\excel.exe'
local file = assert(io.open(fileName, 'rb'))
local t = {}
repeat
   local str = file:read(4*1024)
   for c in (str or ''):gmatch'.' do
      t[#t+1] = c:byte()
   end
until not str
file:close()
print(#t)   --> 18330984

本地文件名为 C:\\Program Files\\Microsoft Office\\Office12\\excel.exe,用 assert 函数打开文件并以二进制方式读取文件 ('rb')。定义一个空表 t,然后反复读取文件中的一定量数据流 str,每次处理 str 中的每个字符并保存其 ASCII 码到表 t 中。最后关闭文件,输出表 t 的长度。

2013-05-12 11:44:16
用户134758
用户134758

如果使用 LuaJIT,另一种方法是读取一定字节数并将其转换为 C 数组。如果一次读取整个文件,则缓冲区应该分配足够的内存来存储它(filesize 个字节)。或者也可以分块读取文件并为每个块重用缓冲区。

使用 C 缓冲区的优点是,它在内存方面比将字节块转换为 Lua 字符串或 Lua 表更有效率。缺点是 FFI 仅支持 LuaJIT。

local ffi = require("ffi")

-- 辅助函数:计算文件大小
local function filesize (fd)
   local current = fd:seek()
   local size = fd:seek("end")
   fd:seek("set", current)
   return size
end

local filename = "example.bin"

-- 以二进制模式打开文件
local fd, err = io.open(filename, "rb")
if err then error(err) end

-- 获取文件大小并为整个文件分配缓冲区
local size = filesize(fd)
local buffer = ffi.new("uint8_t[?]", size)

-- 读取整个文件并将其存储为 C 缓冲区
ffi.copy(buffer, fd:read(size), size)
fd:close()

-- 遍历缓冲区以打印其内容
for i=0,size-1 do
   io.write(buffer[i], " ")
end
2016-03-28 16:24:31