Dir Tree Iterator


The following implementation provides a Lua iterator function that recursively iterates over the files and subdirectories in a given directory.

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

RecentChanges · preferences
edit · history
Last edited January 26, 2013 1:17 pm GMT (diff)

AltStyle によって変換されたページ (->オリジナル) /