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/')