如何在lua中读取大文件(>1GB)?
我是Lua的新手(在Torch7框架中使用它)。我有一个约1.4GB大小(文本文件)的输入特征文件。简单的io.open函数在尝试打开此文件时会抛出“内存不足”的错误。在浏览用户组和文档时,我发现这可能是Lua的限制。是否有解决方法?或者我在读取文件时做错了什么?
local function parse_file(path)
-- 读取文件
local file = assert(io.open(path,"r"))
local content = file:read("*all")
file:close()
-- 按开始/结束标记分割。
local sections = string.split(content, start_tag)
for j=1,#sections do
sections[j] = string.split(sections[j],'\n')
-- 移除结束标记
table.remove(sections[j], #sections[j])
end
return sections
end
local train_data = parse_file(file_loc .. '/' .. train_file)
编辑:我正在尝试读取的输入文件包含我想要训练模型的图像特征。这个文件是有序的({start-tag}...内容...{end-tag}{start-tag}...等等...),所以如果可以逐个加载这些节(从开始标记到结束标记),那就没问题了。然而,我想要将所有这些节加载到内存中。
原来,解决加载大文件的最简单方法是将 Torch 升级到 Lua5.2 或更高版本!正如 Torch 在 torch7-google-group 论坛上开发者所建议的那样。
cd ~/torch
./clean.sh
TORCH_LUA_VERSION=LUA52 ./install.sh
从 5.2 版本开始,内存限制不存在!我已经测试过了,它可以正常工作!
参考:https://groups.google.com/forum/#!topic/torch7/fi8a0RTPvDo
另一个可能的解决方案(更优雅,类似于 @Adam 在他的答案中提出的建议)是逐行读取文件并使用张量或 tds 存储数据,因为它使用 Luajit 之外的内存。以下是一个代码示例,感谢 Vislab。
local ffi = require 'ffi'
-- 此函数逐行加载文件以避免出现内存问题
local function load_file_to_tensor(path)
-- 为文件初始化张量
local file_tensor = torch.CharTensor()
-- 现在我们必须确定张量的最大大小,以便将其分配到内存中。
-- 这必须在一次扫描中分配张量,其中列对应于字母,行对应于文本文件中的行。
--[[ 获取行数和列数 ]]
local file = io.open(path, 'r') -- 打开文件
local max_line_size = 0
local number_of_lines = 0
for line in file:lines() do
-- 获取最大的行大小
max_line_size = math.max(max_line_size, #line +1) -- 加上 1 非常重要,以便正确获取数据
-- 增加行数计数器
number_of_lines = number_of_lines +1
end
file:close() --关闭文件
-- 现在我们已经获得了向量的最大大小,只需要为它分配内存即可(只要内存够大)
file_tensor = file_tensor:resize(number_of_lines, max_line_size):fill(0)
local f_data = file_tensor:data()
-- 唯一剩下的事情就是从文件中获取数据到张量中。
-- 让我们再次打开文件并使用 ffi 来填充张量
local file = io.open(path, 'r') -- 打开文件
for line in file:lines() do
-- 逐行将数据复制到张量中
ffi.copy(f_data, line)
f_data = f_data + max_line_size
end
file:close() --关闭文件
return file_tensor
end
从这个张量中读取数据很简单快捷。例如,如果您要读取文件中的第十行(将在张量的第十个位置),则可以简单地执行以下操作:
local line_string = ffi.string(file_tensor[10]:data()) -- 这将转换为字符串变量
警告:这将占用更多的内存空间,对于一些行比其他行长得多的情况可能不是最优选。但是,如果您没有内存问题,这甚至可以被忽略,因为将张量从文件加载到内存中时速度非常快,并且可能会在过程中节省一些头发。
参考:https://groups.google.com/forum/#!topic/torch7/fi8a0RTPvDo
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
我从未需要阅读如此大的文件,但如果你的内存不够,你可能需要逐行阅读它。在进行了一些快速研究后,我从Lua网站找到了这个:
buff = buff..line.."\n"buff是一个包含50,020字节的新字符串,旧字符串现在被丢弃。经过两个循环周期,buff是一个包含50,040字节的字符串,有两个旧字符串,总共超过100 Kbytes的垃圾。因此,Lua决定非常正确地运行垃圾回收器,释放这100 Kbytes。问题是这将在每两个周期发生一次,因此Lua会在完成循环之前运行它的垃圾回收器两千次。即使进行了所有这些工作,它的内存使用量也将是文件大小的三倍左右。更糟糕的是,每次连接都必须将整个字符串内容(50 Kbytes和增长)复制到新字符串中。
因此,即使你按照以下方式逐行阅读并每次使用连接,加载大文件似乎会使用大量内存:
local buff = "" while 1 do local line = read() if line == nil then break end buff = buff..line.."\n" end他们随后提出了一种更加节省内存的处理方式:
function newBuffer () return {n=0} -- 'n' counts number of elements in the stack end function addString (stack, s) table.insert(stack, s) -- push 's' into the top of the stack for i=stack.n-1, 1, -1 do if string.len(stack[i]) > string.len(stack[i+1]) then break end stack[i] = stack[i]..table.remove(stack) end end function toString (stack) for i=stack.n-1, 1, -1 do stack[i] = stack[i]..table.remove(stack) end return stack[1] end比以前使用更少的内存。所有信息都来自于:http://www.lua.org/notes/ltn009.html
希望有所帮助。