Dir Tree Iterator |
|
It depends on the LuaFileSystem library ("lfs"
) [1].
-- code by AlexanderMarinov -- Compatible with Lua 5.1 (not 5.0). require "lfs" function dirtree(dir) assert(dir and dir ~= "", "directory parameter is missing or empty") if string.sub(dir, -1) == "/" then dir=string.sub(dir, 1, -2) end local diriters = {lfs.dir(dir)} local dirs = {dir} return function() repeat local entry = diriters[#diriters]() if entry then if entry ~= "." and entry ~= ".." then local filename = table.concat(dirs, "/").."/"..entry local attr = lfs.attributes(filename) if attr.mode == "directory" then table.insert(dirs, entry) table.insert(diriters, lfs.dir(filename)) end return filename, attr end else table.remove(dirs) table.remove(diriters) end until #diriters==0 end end
A more concise version using coroutines would be
-- Code by David Kastrup require "lfs" function dirtree(dir) assert(dir and dir ~= "", "directory parameter is missing or empty") if string.sub(dir, -1) == "/" then dir=string.sub(dir, 1, -2) end local function yieldtree(dir) for entry in lfs.dir(dir) do if entry ~= "." and entry ~= ".." then entry=dir.."/"..entry local attr=lfs.attributes(entry) coroutine.yield(entry,attr) if attr.mode == "directory" then yieldtree(entry) end end end end return coroutine.wrap(function() yieldtree(dir) end) end
Example usage when the current directory (.
) is the Lua source directory:
> -- example > for filename, attr in dirtree(".") do >> print(attr.mode, filename) >> end file ./COPYRIGHT directory ./doc file ./doc/contents.html file ./doc/logo.gif file ./doc/lua.1 file ./doc/lua.css file ./doc/lua.html file ./doc/luac.1 file ./doc/luac.html file ./doc/manual.html file ./doc/readme.html directory ./etc file ./etc/all.c file ./etc/lua.hpp file ./etc/lua.ico file ./etc/lua.pc file ./etc/luavs.bat file ./etc/Makefile file ./etc/min.c file ./etc/noparser.c file ./etc/README file ./etc/strict.lua file ./HISTORY file ./INSTALL file ./Makefile file ./README directory ./src file ./src/lapi.c file ./src/lapi.h file ./src/lauxlib.c file ./src/lauxlib.h file ./src/lbaselib.c file ./src/lcode.c file ./src/lcode.h file ./src/ldblib.c file ./src/ldebug.c file ./src/ldebug.h file ./src/ldo.c file ./src/ldo.h file ./src/ldump.c file ./src/lfunc.c file ./src/lfunc.h file ./src/lgc.c file ./src/lgc.h file ./src/linit.c file ./src/liolib.c file ./src/llex.c file ./src/llex.h file ./src/llimits.h file ./src/lmathlib.c file ./src/lmem.c file ./src/lmem.h file ./src/loadlib.c file ./src/lobject.c file ./src/lobject.h file ./src/lopcodes.c file ./src/lopcodes.h file ./src/loslib.c file ./src/lparser.c file ./src/lparser.h file ./src/lstate.c file ./src/lstate.h file ./src/lstring.c file ./src/lstring.h file ./src/lstrlib.c file ./src/ltable.c file ./src/ltable.h file ./src/ltablib.c file ./src/ltm.c file ./src/ltm.h file ./src/lua.c file ./src/lua.h file ./src/luac.c file ./src/luaconf.h file ./src/lualib.h file ./src/lundump.c file ./src/lundump.h file ./src/lvm.c file ./src/lvm.h file ./src/lzio.c file ./src/lzio.h file ./src/Makefile file ./src/print.c directory ./test file ./test/bisect.lua file ./test/cf.lua file ./test/echo.lua file ./test/env.lua file ./test/factorial.lua file ./test/fib.lua file ./test/fibfor.lua file ./test/globals.lua file ./test/hello.lua file ./test/life.lua file ./test/luac.lua file ./test/printf.lua file ./test/README file ./test/readonly.lua file ./test/sieve.lua file ./test/sort.lua file ./test/table.lua file ./test/trace-calls.lua file ./test/trace-globals.lua file ./test/xd.lua
Another method using "lfs".
require "lfs" -- code by GianlucaVespignani - 2012-03-04; 2013-01-26 -- Search files in a path, alternative in sub directory -- @param dir_path string (";" for multiple paths supported) -- @param filter string - eg.: ".txt" or ".mp3;.wav;.flac" -- @param s bool - search in subdirectories -- @param pformat format of data - 'system' for system-dependent number; nil or string with formatting directives -- @return files, dirs - files and dir are tables {name, modification, path, size} function file_search(dir_path, filter, s, pformat) -- === Preliminary functions === -- comparison function like the IN() function like SQLlite, item in a array -- useful for compair table for escaping already processed item -- Gianluca Vespignani 2012-03-03 local c_in = function(value, tab) for k,v in pairs(tab) do if v==value then return true end end return false end local string = string -- http://lua-users.org/wiki/SplitJoin function string:split(sep) local sep, fields = sep or ":", {} local pattern = string.format("([^%s]+)", sep) self:gsub(pattern, function(c) fields[#fields+1] = c end) return fields end local ExtensionOfFile = function(filename) local rev = string.reverse(filename) local len = rev:find("%.") local rev_ext = rev:sub(1,len) return string.reverse(rev_ext) end -- === Init === dir_path = dir_path or cwd filter = string.lower(filter) or "*" extensions = filter:split(";") s = s or false -- as /s : subdirectories if pformat == 'system' then -- if 4th arg is explicity 'system', then return the system-dependent number representing date/time os_date = function(os_time) return os_time end else -- if 4th arg is nil use default, else it could be a string that respects the Time formatting directives pformat = pformat or "%Y/%m/%d" -- eg.: "%Y/%m/%d %H:%M:%S" os_date = function(os_time) return os.date(pformat, os_time) end end -- == MAIN == local files = {} local dirs = {} local paths = dir_path:split(";") for i,path in ipairs(paths) do for f in lfs.dir(path) do if f ~= "." and f ~= ".." then local attr = lfs.attributes ( path.."/"..f ) if attr.mode == "file" then if filter=="*" or c_in( string.lower( ExtensionOfFile(f) ), extensions) then table.insert(files,{ name = f, modification = os_date(attr.modification) , path = path.."/", size = attr.size }) end else if filter=="*" then -- if attr.mode == "directory" and file ~= "." and file ~= ".." then end table.insert(dirs,{ name = f , modification = os_date(attr.modification) , path = path.."/", size = attr.size }) end if s and attr.mode == "directory" then local subf={} local subd={} subf, subd = file_search(path.."/"..f, filter, s, pformat) for i,v in ipairs(subf) do table.insert(files,{ name = v.name , modification = v.modification , path = v.path, size = v.size }) end for i,v in ipairs(subd) do table.insert(dirs,{ name = v.name , modification = v.modification , path = v.path, size = v.size }) end end end end end end return files,dirs --[=[ ABOUT ATTRIBUTES > for k,v in pairs(a) do print(k..' \t'..v..'') end dev 2 change 1175551262 -- date of file Creation access 1235831652 rdev 2 nlink 1 uid 0 gid 0 ino 0 mode file modification 1181692021 -- Date of Last Modification size 805 in byte ]=] end