Dir Tree Iterator

lua-users home
wiki

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 6:17 pm GMT (diff)