【问题标题】:lua Custom Directory Iteratorlua 自定义目录迭代器
【发布时间】:2017-03-02 10:11:06
【问题描述】:

我正在使用不支持 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("")

代码给了我“堆栈溢出”的错误。

SetDIR 使用 API:FileSetDir(RootDir) 设置目录并获取 RootDirList1 表中的文件列表。然后我在这里调用函数 CheckDirectory() 如果表条目是文件,我将在 RootDirList1 表上运行 for 循环,它将存储到 finalpath 表中。如果表项是目录,那么它调用 SetDIR 来获取该目录中的文件列表。

我知道我的方法是错误的,因此任何聪明的想法都将不胜感激。

【问题讨论】:

  • 检查字符串中多余的“或” if string.find(v,"%.mkv$") or string.find(v,"%.mp4$") or then"
  • 哦,这是一个错字,原来的代码没有这个。
  • 函数 CheckDirectory() - 无参数的无休止调用
  • 好的 注意到了。我正在尝试更动态地实现它。就像它第一次运行时获取主目录列表,然后遍历主列表中的每个目录,直到找到所有文件。
  • CheckDirectory(v) 是什么意思? CheckDirectory 没有参数!

标签: list lua iterator directory lua-table


【解决方案1】:

堆栈溢出 (heh) 意味着堆栈正在溢出——它已满。堆栈基本上是一个内存区域,实际上就像 IRL 堆栈的东西:您可以在上面放置一些东西(推)或取回它(弹出)。

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

【讨论】:

  • 哇好安静。没有 CPU 打嗝。唯一的问题是所有路径最后都有相同的电影名称。 “在南极洲之下 - 完整的纪录片 HD.mp4”
  • /mnt/media/net/192.168.1.40_usbshare2/Movies/3D 电影/Yogi Bear 3D/在南极洲 - 完整纪录片 HD.mp4 /mnt/media/net/192.168.1.40_usbshare2/电影/3D 电影/TRON Legacy (2010) [3D] [HSBS]/Under the Antarctica - Full Documentary HD.mp4 等....
  • 最后我忘了把t改成v。固定的。 (您可能将全局 t 定义为该字符串)
【解决方案2】:

我使用 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)

【讨论】:

  • 我正在使用的系统不支持 Ifs 库。
  • @Prakash.DTI 但是你有一个我没有的 API。替换你的函数。
  • 替代品是什么意思?
  • 在----之前不要使用我的块
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 2012-11-06
  • 2013-02-17
  • 2015-11-19
  • 2013-09-02
  • 2020-05-27
相关资源
最近更新 更多