lua 自定义目录迭代器
lua Custom Directory Iterator
我正在使用不支持 lua 文件系统库的系统。所以我必须制作自己的目录迭代器,它会为我提供具有特定格式的完整路径的文件列表。
系统有一个 API 我们可以设置目录路径和另一个 API 以 lua table 格式获取该目录中的文件列表。
API:FileSetDir() 设置要获取文件列表的目录。
API:FileList() 从我们使用 API:FileSetDir() 设置的目录中给出 table 文件列表。
例如考虑以下目录结构。
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 中的文件列表table。然后我在这里调用函数 CheckDirectory() 我是 运行 RootDirList1 table 上的 for 循环如果 table 条目是文件,它将被存储到最终路径 table。如果 table 条目是目录,则它调用 SetDIR 以获取该目录中的文件列表。
我知道我的方法是错误的,如果有任何好主意,我们将不胜感激。
我使用 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)
Stack overflow (heh) 意思是,嗯,堆栈溢出了——满了。堆栈基本上是一个内存区域,它实际上就像一个 IRL 堆栈:您可以将某些东西放在它上面(推入)或取回它(弹出)。
Lua 有不止一层。这里重要的是 调用堆栈 :当你调用一个函数时,你将一个值压入它(在它之后恢复的地方 returns)。它是有限的,所以你不能消耗无限的内存。
所以,基本上,您的代码会导致无限递归。它调用自己并没有进行,所以它只是填满内存而什么都不做。
也就是说,你的错误是在这一行:
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/')
我正在使用不支持 lua 文件系统库的系统。所以我必须制作自己的目录迭代器,它会为我提供具有特定格式的完整路径的文件列表。
系统有一个 API 我们可以设置目录路径和另一个 API 以 lua table 格式获取该目录中的文件列表。
API:FileSetDir() 设置要获取文件列表的目录。 API:FileList() 从我们使用 API:FileSetDir() 设置的目录中给出 table 文件列表。
例如考虑以下目录结构。
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 中的文件列表table。然后我在这里调用函数 CheckDirectory() 我是 运行 RootDirList1 table 上的 for 循环如果 table 条目是文件,它将被存储到最终路径 table。如果 table 条目是目录,则它调用 SetDIR 以获取该目录中的文件列表。
我知道我的方法是错误的,如果有任何好主意,我们将不胜感激。
我使用 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)
Stack overflow (heh) 意思是,嗯,堆栈溢出了——满了。堆栈基本上是一个内存区域,它实际上就像一个 IRL 堆栈:您可以将某些东西放在它上面(推入)或取回它(弹出)。
Lua 有不止一层。这里重要的是 调用堆栈 :当你调用一个函数时,你将一个值压入它(在它之后恢复的地方 returns)。它是有限的,所以你不能消耗无限的内存。
所以,基本上,您的代码会导致无限递归。它调用自己并没有进行,所以它只是填满内存而什么都不做。
也就是说,你的错误是在这一行:
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/')