lua自定义目录迭代器

我正在处理一个不支持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)
   如果v ==“” then
       RootDir = '/ mnt / media / net / 192.168.1.40_usbshare1 / Movies /'
   else
       RootDir = '/ mnt / media / net / 192.168.1.40_usbshare1 / Movies /' .. v
     结束
     API:FileSetDir(RootDir)
     RootDirList1 = API:FileList()
     CheckDirectory()
结束

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()
       如果RootDirList == nil则
           打印(v)
打印(“不是目录”)
           如果string.find(v,“%。mkv $”)或string.find(v,“%。mp4 $”)then
               finalpath [#finalpath + 1] = RootDir ..“ /”..t
                打印(RootDir ..“ /”..t)

           结束
           else
             CheckDirectory(v)
       结束
   结束
结束

SetDIR(“”)

这段代码报告错误“堆栈溢出”。

SetDIR使用API:FileSetDir(RootDir)设置目录并在RootDirList1表中获取文件列表。然后在此处调用CheckDirectory()函数,我正在对RootDirList1表执行for循环,如果表条目是文件,则将其存储在finalpath表中。如果表条目是目录,则调用SetDIR以获得该目录中的文件列表。

我知道我的方法是错误的,如果有任何聪明的想法,将不胜感激。

点赞
用户7504558
用户7504558

我使用了lfs模块模拟了你的API,并编写了可行的代码:

-- 我的代码块。请勿在你的项目中使用。 ------
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
--- 我的代码块结束 ----------------------------------------------------
local finalpath={}
local RootDir = 'd:/temp'

function CheckDirectory(entry)
        local CurDir = entry
        local IsDir = API:FileSetDir(CurDir)  -- 出现错误时返回 nil 
        local DirList = API:FileList()
        print(CurDir)
        if not  IsDir  then
                    print(CurDir .." - 不是目录")
        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 
                                        finalpath[#finalpath+1] = tmp
                                        print(' >> '..tmp)
                                end
                                if not (v=='.' or v=='..') then
                                  CheckDirectory(tmp)
                                end
                    end
        end
end

CheckDirectory(RootDir)
2017-03-02 13:10:16
用户6484173
用户6484173

Stack Overflow

"Stack overflow"意味着堆栈已满。堆栈是一块内存区域,就像一个实际物品的堆栈:你可以把一个东西放在它的顶部(push),或者取回(pop)一个东西。

Lua具有多个堆栈。这里的一个重要堆栈是_call stack_:当你调用一个函数时,你将一个值推入它(指向在它返回后要恢复的位置)。它是有限的,因此您无法消耗无限的内存。

所以,基本上,你的代码引起了无限递归。它调用自己并没有进展,所以它只是填满了内存而且什么也没干。

话虽如此,你的错误在这一行中:

local RootDir = '/mnt/media/net/192.168.1.40_usbshare1/Movies/'..v

你想递归列出文件,对吧?那不是递归。这一行假定文件在根目录"Movies"中,这会生成无限递归,因为它反复检查相同的文件夹,一遍又一遍,一次又一次。你应该将其附加到当前的RootDir上。

我认为CheckDirectory(v)在此也起着一定作用。这意味着什么?CheckDirectory没有参数!(感谢Egor指出)

在下面,我重构了你的代码,完全改变了操作方式,使之更加高效,并修复了标识问题。

function CheckDirectory(dir)
    local result = {}

    --将目录设置为dir,然后列出它
    API:FileSetDir(dir)
    local list = API:FileList()

    for i, v in pairs(list) do
        API:FileSetDir(dir .. v .. "/") --已修正

        local clist = API:FileList()

        --不要与nil比较。只需使用'not clist'即可。此外,我们有一个else,所以我颠倒了一切,并将else .. if折叠为elseif。
        if not clist then
            if string.find(v, "%.mkv$") or string.find(v, "%.mp4$") then
                table.insert(result, dir .. v)
                print(dir .. v) --如果不想打印,则删除此行
            end
        else
            for i, v in ipairs(CheckDirectory(dir .. v .. "/")) do
                table.insert(result, v)
            end
        end
    end

    return result
end

local files = CheckDirectory('/mnt/media/net/192.168.1.40_usbshare1/Movies/')
2017-06-26 18:39:53