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