【问题标题】:How to get list of directories in Lua如何在 Lua 中获取目录列表
【发布时间】:2011-07-15 06:16:35
【问题描述】:

我需要 LUA 中的目录列表

假设我有一个目录路径为“C:\Program Files”

我需要该特定路径中所有文件夹的列表以及如何搜索该列表中的任何特定文件夹。

例子

需要路径“C:\Program Files”中所有文件夹的列表

以下是上述路径中的文件夹名称

  1. test123

  2. test4567

  3. 文件夹 123

  4. 文件夹 456

  5. 文件夹 456 789

    需要在列表中获取上述内容,然后必须仅在文件夹 456 789 中搜索特定字符串,例如文件夹 456。

已尝试以下代码。我在下面缺少的东西:-

local function Loc_Lines( str )
--
local ret= {}   -- 0 lines

while str do
    local _,_,line,tail= string.find( str, "(.-)\n(.+)" )
    table.insert( ret, line or str )
    str= tail
  Print (str)
end

return ret
end


local function Loc_ShellCommand( cmd )
--
local str= nil

    --
    local f= io.popen( cmd )    -- no command still returns a handle :(
     if f then

        str= f:read'*a'
    Print(str)
        f:close()
    end
    
    if str=="" then   -- take no output as a failure (we can't tell..)
    Print("hi")
        str= nil
    end
 
-- Remove terminating linefeed, if any (eases up one-line analysis)
--
if str then
    if string.sub( str, -1 ) == '\n' then
        str= string.sub( str, 1, -2 )
    end
end

return str
 end


 local function Loc_DirCmd( cmd )

 Print(cmd)

  local str= Loc_ShellCommand( cmd )



 return Loc_Lines(str)
 end


local function Loc_DirList( dirname )

 local ret= {}
  
    local lookup= {}

   local tbl= Loc_DirCmd( "dir /AD /B "..dirname )   -- only dirs

    -- Add slash to every dir line
    --
    for i,v in ipairs(tbl) do
        table.insert( ret, v..'\\' )
        lookup[v]= true
    end       

    
    -- Return with forward slashes
    --
    if true then
        for i=1,table.getn(ret) do
            ret[i]= string.gsub( ret[i], '\\', '/' )
     Print (ret[i])
        end
    end
  

   return ret
 end


 Loc_DirList("C:\\Program Files\\")

【问题讨论】:

    标签: lua filenames directory-listing


    【解决方案1】:

    我讨厌必须安装库(尤其是那些希望我使用安装程序包来安装它们的库)。如果您正在为 Lua 中绝对路径上的目录列表寻找一个干净的解决方案,请不要再犹豫了。

    基于 sylvanaar 提供的答案,我创建了一个函数,该函数返回给定目录的所有文件的数组(需要绝对路径)。这是我的首选实现,因为它适用于我的所有机器。

    -- Lua implementation of PHP scandir function
    function scandir(directory)
        local i, t, popen = 0, {}, io.popen
        local pfile = popen('ls -a "'..directory..'"')
        for filename in pfile:lines() do
            i = i + 1
            t[i] = filename
        end
        pfile:close()
        return t
    end
    

    如果您使用的是 Windows,则需要安装 bash 客户端,这样“ls”命令才能工作 - 或者,您可以使用 sylvanaar 提供的 dir 命令:

    'dir "'..directory..'" /b /ad'
    

    【讨论】:

    • 请注意:您的代码为您提供所有文件;给定的 dir 命令只为您提供目录。要获取所有文件,只需使用dir <path> /b(省略/ad,它只指定目录。)
    • 你可以重新编译一个包含 lfs.h 和 lfs.c 的 lua 库。这就是我为“安装”lfs 所做的。
    • 不解析ls
    • 当目录名称包含单引号(可能还有其他讨厌的字符)时,这会非常糟糕。记住 POSIX 文件名只是字节字符串。
    • 不解析ls的输出。请改用find -maxdepth 1 -print0ls 的问题在于实现之间存在许多不一致,并且很少(如果有)允许使用文件名不能包含的分隔符(它们可以包含换行符!),最常见的是空字节,但斜杠可能也可以工作。
    【解决方案2】:

    采取简单的方法,安装lfs。然后使用以下构造找到您需要的内容:

    require'lfs'
    for file in lfs.dir[[C:\Program Files]] do
        if lfs.attributes(file,"mode") == "file" then print("found file, "..file)
        elseif lfs.attributes(file,"mode")== "directory" then print("found dir, "..file," containing:")
            for l in lfs.dir("C:\\Program Files\\"..file) do
                 print("",l)
            end
        end
    end
    

    请注意,反斜杠等于[[\]] 等于"\\",如果在 cmd 本身上不使用,也允许在 windows / 中使用(如果我在这个上错了,请纠正我)。

    【讨论】:

    • 为了让它为我工作,我必须使用一个具有完全限定路径名的文件。即 lfs.attributes("C:\\Program Files\\" .. file, "mode") 另外,你应该考虑过滤掉 "."和“..”,至少在 Linux 系统上。
    【解决方案3】:

    我也不喜欢安装库,并且正在使用内存容量比 pc 更少的嵌入式设备。我发现使用“ls”命令会导致内存不足。所以我创建了一个使用'find'来解决问题的函数。

    这样可以保持内存使用稳定并循环所有 30k 文件。

    function dirLookup(dir)
       local p = io.popen('find "'..dir..'" -type f')  --Open directory look for files, save data in p. By giving '-type f' as parameter, it returns all files.     
       for file in p:lines() do                         --Loop through all files
           print(file)       
       end
    end
    

    【讨论】:

    • 这似乎是没有库的最佳答案,它在 Windows 中有效吗?
    • @DanielJordi 我不这么认为;在 Windows 中,命令 find 是 grep 的对应物,而不是文件查找器。
    • 这个函数会递归遍历树,而不仅仅是列出目录。
    • 要正确处理包含换行符的文件名,请使用 find ... -print0 并拆分空字节。您可能还想添加 -maxdepth 1 以避免递归到子目录。
    【解决方案4】:
     for dir in io.popen([[dir "C:\Program Files\" /b /ad]]):lines() do print(dir) end
    

    *适用于 Windows

    输出:

    Adobe
    Bitcasa
    Bonjour
    Business Objects
    Common Files
    DVD Maker
    IIS
    Internet Explorer
    iPod
    iTunes
    Java
    Microsoft Device Emulator
    Microsoft Help Viewer
    Microsoft IntelliPoint
    Microsoft IntelliType Pro
    Microsoft Office
    Microsoft SDKs
    Microsoft Security Client
    Microsoft SQL Server
    Microsoft SQL Server Compact Edition
    Microsoft Sync Framework
    Microsoft Synchronization Services
    Microsoft Visual Studio 10.0
    Microsoft Visual Studio 9.0
    Microsoft.NET
    MSBuild
    ...
    

    每次循环都会给你一个新的文件夹名称。我选择打印它作为示例。

    【讨论】:

    • 注意:要获取文件列表,只能使用/b 而不是/b /ad
    【解决方案5】:

    IIRC,使用股票 Lua 无法获取目录列表。你需要自己写一些胶水代码,或者使用LuaFileSystem。后者很可能是您阻力最小的路径。快速浏览文档会显示lfs.dir(),它将为您提供一个迭代器,您可以使用它来获取您正在寻找的目录。此时,您可以进行字符串比较以获得所需的特定目录。

    【讨论】:

    • 请检查我在获取列表时是否遗漏了什么。
    • 厌倦了你的建议我在这里缺少的东西
    • (问题已更新以包含 OP 正在使用的代码,当我写我的答案时它并不存在。)公平点,我没有提到你可以用 io.popen() .我假设您正在寻找一种通用的方式来执行此操作,而不是 Windows 特定的方式。我没有一个 Windows 盒子来试试这个。也许你可以用你得到的结果和你期望得到的结果来更新你的问题。
    • @che - 据我所知,您还没有尝试过我的建议,您选择了使用平台特定选项的路线。正如我已经指出的那样,我没有带有 Lua 的 Windows 框来尝试为您追踪您的问题,特别是因为您没有提供您获得的输出以及您期望的输出。
    • 这是我正在寻找的答案,可以通过 require "lfs" hFile = io.popen('dir /a:d /b "C:\\Program Files\\"') line = hFile:read('*l') while (line ~= nil) do Print(line) line = hFile:read('*l') end
    【解决方案6】:

    您还可以安装和使用“paths”模块。然后您可以轻松地执行以下操作:

    require 'paths'
    
    currentPath = paths.cwd() -- Current working directory
    folderNames = {}
    for folderName in paths.files(currentPath) do
        if folderName:find('$') then
            table.insert(folderNames, paths.concat(currentPath, folderName))
        end
    end
    
    print (folderNames)
    

    -- 这将打印所有文件夹名称

    或者,您还可以通过将fileName:find('$') 替换为fileName:find('txt' .. '$') 来查找具有特定扩展名的文件名

    如果您在基于 Unix 的机器上运行,您可以使用以下代码获得数字排序的文件列表:

    thePath = '/home/Your_Directory'
    local handle = assert(io.popen('ls -1v ' .. thePath)) 
    local allFileNames = string.split(assert(handle:read('*a')), '\n')
    
    print (allFileNames[1]) -- This will print the first file name
    

    第二个代码也排除了诸如“.”之类的文件。和 '..'。所以很高兴去!

    【讨论】:

    • 我发现paths.files(currentPath) 会返回一个未排序的结果。如何对它们进行排序。有for file in sort(paths.files(currentPath)) do这样的代码吗?
    • @C.Wang 请再次检查我的答案。我用适合您任务的代码更新了它
    【解决方案7】:

    不要解析ls,这是邪恶的!将find 与以零结尾的字符串一起使用(在Linux 上):

    function scandir(directory)
        local i, t = 0, {}
        local pfile = assert(io.popen(("find '%s' -maxdepth 1 -print0"):format(directory), 'r'))
        local list = pfile:read('*a')
        pfile:close()
        for filename in s:gmatch('[^\0]+')
            i = i + 1
            t[i] = filename
        end
        return t
    end
    

    警告:但是,作为公认的答案,如果目录名称中包含',则可以利用此方法。只有一种安全的解决方案是使用lfs 或其他特殊库。

    【讨论】:

      【解决方案8】:

      val says Reinstate Monica 解决方案的一些修复:

      function scandir(directory)
          local pfile = assert(io.popen(("find '%s' -mindepth 1 -maxdepth 1 -type d -printf '%%f\\0'"):format(directory), 'r'))
          local list = pfile:read('*a')
          pfile:close()
      
          local folders = {}
      
          for filename in string.gmatch(list, '[^%z]+') do
              table.insert(folders, filename)
          end
      
          return folders
      end
      

      现在它按文件夹过滤,排除 dir 本身并仅打印名称。

      【讨论】:

        猜你喜欢
        • 2012-04-22
        • 2011-02-11
        • 2020-07-24
        • 2013-02-02
        • 2010-09-17
        • 1970-01-01
        • 2016-01-12
        • 2022-01-15
        相关资源
        最近更新 更多