我正在开发一个不支持lua文件系统库的系统。所以我必须创建自己的目录迭代器,它给出了具有特定格式的完整路径的文件列表。
系统有一个我们可以为目录路径设置的API,另一个API用于以lua表格式获取该目录中的文件列表。
API:FileSetDir()将目录设置为获取文件列表。 API:FileList()给出了我们使用API设置的目录中的文件列表表:FileSetDir()。
例如,请考虑以下目录结构。
Movies/3d Movies/Avatar/Avatar.mp4
Movies/3d Movies/Avengers/Avengers.mkv
Movies/3d Movies/ironman.mp4
Movies/Horor/Ring/Ring.avi
Movies/Horor/A Nightmare On Elm Street/A Nightmare On Elm Street.iso
Movies/Barfi.mkv
我的代码..
RootDirList1 = {}
RootDirList = {}
finalpath={}
function SetDIR(v)
if v=="" then
RootDir = '/mnt/media/net/192.168.1.40_usbshare1/Movies/'
else
RootDir = '/mnt/media/net/192.168.1.40_usbshare1/Movies/'..v
end
API:FileSetDir (RootDir)
RootDirList1 = API:FileList ()
CheckDirectory()
end
function CheckDirectory()
for i,v in pairs(RootDirList1) do
local RootDir = '/mnt/media/net/192.168.1.40_usbshare1/Movies/'..v
API:FileSetDir (RootDir)
local RootDirList = API:FileList ()
if RootDirList == nil then
print(v)
print("Not Directory")
if string.find(v,"%.mkv$") or string.find(v,"%.mp4$") then
finalpath[#finalpath+1] =RootDir.."/"..t
print(RootDir.."/"..t)
end
else
CheckDirectory(v)
end
end
end
SetDIR("")
代码在" Stack Overflow"。
中给出了错误SetDIR使用API设置目录:FileSetDir(RootDir)并获取RootDirList1表中的文件列表。然后我调用函数CheckDirectory()这里我在RootDirList1表上运行for循环,如果表项是文件,它将存储在finalpath表中。如果表条目是目录,则它调用SetDIR以获取该目录中的文件列表。
我知道我的方法是错误的,使这项工作任何好主意都会受到高度赞赏。
答案 0 :(得分:2)
堆栈溢出(heh)意味着堆栈溢出 - 它已满。堆栈基本上是一个内存区域,就像IRL堆栈一样:你可以在它上面放置一些东西(推送)或者把它取回(pop)。
Lua有多个筹码。这里重要的是调用堆栈:当你调用一个函数时,你将一个值推送到它(返回后恢复的位置)。它是有限的,所以你不能消耗无限的记忆。
因此,基本上,您的代码会导致无限递归。它会调用自身并且不会进展,因此它只会填满内存而不会执行任何操作。
话虽如此,你的错误就在这一行:
local RootDir = '/mnt/media/net/192.168.1.40_usbshare1/Movies/'..v
你试图递归列出 ,对吧?这根本不是递归的。该行假设该文件位于根文件夹“Movies”中,该文件夹生成无限递归,因为它一遍又一遍地反复检查同一文件夹。相反,您应该附加到当前的RootDir
。
我认为CheckDirectory(v)
也参与其中。那是什么意思? CheckDirectory
没有参数! (感谢Egor指出这一点)
下面,我重构了您的代码,完全改变了操作以提高效率,并修复了身份问题。
function CheckDirectory(dir)
local result = {}
-- set directory to dir, then list it
API:FileSetDir(dir)
local list = API:FileList()
for i, v in pairs(list) do
API:FileSetDir(dir .. v .. "/") -- fixed!
local clist = API:FileList()
-- don't compare to nil. Just use 'not clist'.
-- And besides, we have an else, so I inverted everything
-- and collapsed the else .. if into elseif.
if clist then
for i, v in ipairs(CheckDirectory(dir .. v .. "/")) do
table.insert(result, v)
end
elseif string.find(v, "%.mkv$") or string.find(v, "%.mp4$") then
table.insert(result, dir .. v)
print(dir .. v) -- remove this line if you don't want to print
end
end
return result
end
local files = CheckDirectory('/mnt/media/net/192.168.1.40_usbshare1/Movies/')
答案 1 :(得分:0)
我使用lfs模拟了您的API并编写了有效的代码:
-- My block. Do not use in your project. ------
local lfs = require "lfs"
local API = { }
function API:FileSetDir(path)
return lfs.chdir (path)
end
function API:FileList()
local path= lfs.currentdir ()
local t = {}
for entry in lfs.dir(path) do
t[#t+1] = entry
end
return t
end
--- End of my block ----------------------------------------------------
local finalpath={}
local RootDir = 'd:/temp'
function CheckDirectory(entry)
local CurDir = entry
local IsDir = API:FileSetDir(CurDir) -- return nil when error
local DirList = API:FileList()
print(CurDir)
if not IsDir then
print(CurDir .." - Not Directory")
else
for _,v in pairs(DirList) do
local tmp = CurDir.."/".. v
if true or string.find(v,"%.mkv$") or string.find(v,"%.mp4$") then -- true always for me
finalpath[#finalpath+1] = tmp
print(' >> '..tmp)
end
if not (v=='.' or v=='..') then
CheckDirectory(tmp)
end
end
end
end
CheckDirectory(RootDir)