在lua中如何检查文件夹是否存在?

20

如何在lua中检查目录是否存在,最好不使用LuaFileSystem模块?

尝试像Python代码这样实现:

os.path.isdir(path)
13个回答

28

这是一种适用于Unix和Windows的方式,没有任何外部依赖:

--- Check if a file or directory exists in this path
function exists(file)
   local ok, err, code = os.rename(file, file)
   if not ok then
      if code == 13 then
         -- Permission denied, but it exists
         return true
      end
   end
   return ok, err
end

--- Check if a directory exists in this path
function isdir(path)
   -- "/" works on both Unix and Windows
   return exists(path.."/")
end

8
非常聪明,使用 os.rename 进行那个操作。 - Lucas Siqueira
仅供参考,第三个返回值是Lua 5.2的功能。(请参阅5.15.2参考手册。)虽然未记录,但似乎在LuaJIT中得到支持。 - Elliott Slaughter
你可能需要传递绝对路径给 os.rename 而不是相对路径,以使你的代码更加稳定。 - VimNing

16
问题在于标准Lua发行版(几乎)仅包括标准C中指定的功能。标准C并不假定实际上存在任何特定类型的文件系统(或者甚至操作系统),因此osio模块不提供标准C库中无法获得的访问信息。
如果您试图以纯标准C编码,将遇到相同的问题。
有一种可能性是可以从尝试使用它来隐式地了解文件夹是否存在。如果您希望它存在并且可由您编写,则创建一个临时文件并在那里进行操作,如果成功,则文件夹存在。当然,如果失败,您可能无法区分不存在的文件夹和权限不足。
最轻量级的答案是绑定到仅提供所需信息的那些特定于操作系统的函数调用。如果您可以接受lua alien模块,则可以在纯Lua中执行绑定。
更简单但略微重量级的方法是使用Lua文件系统。它提供了一个可移植的模块,支持大多数有关文件和文件系统的查询。

9
如果您特别想避免使用LFS库,Lua Posix库具有与stat()的接口。
require 'posix'
function isdir(fn)
    return (posix.stat(fn, "type") == 'directory')
end

LuaPosix库非常庞大,而且在Unix和Windows之间不可移植。 - Hisham H M

6
好的,参考手册5.1版在操作系统表中没有任何内容,但是如果您使用Nixstaller,则可以获得os.fileexists,完全符合您所解释的内容。
如果可以稍微尝试一下,或者如果您知道要运行的操作系统,您可能可以通过标准的os库的os.execute函数以及识别文件是否存在的某些系统调用来实现。
os.execute更好的方法是os.rename:

os.rename(oldname, newname)

将名为oldname的文件重命名为newname。 如果此函数失败,则返回 nil,以及描述错误的字符串。

您可以尝试将oldname和newname设置为相同--但是您可能没有写入权限,因此它可能会由于无法写入而失败,即使您可以阅读。 在这种情况下,您必须解析返回的错误字符串并推断是否可以写入,或者您必须尝试执行需要现有文件的函数,并将其包装在pcall中。

4
你也可以使用“paths”软件包。这里是软件包的链接。
然后在Lua中执行:
require 'paths'

if paths.dirp('your_desired_directory') then
    print 'it exists'
else
    print 'it does not exist'
end

3

我使用这些(但实际上我会检查错误):


require("lfs")
-- no function checks for errors.
-- you should check for them

function isFile(name)
    if type(name)~="string" then return false end
    if not isDir(name) then
        return os.rename(name,name) and true or false
        -- note that the short evaluation is to
        -- return false instead of a possible nil
    end
    return false
end

function isFileOrDir(name)
    if type(name)~="string" then return false end
    return os.rename(name, name) and true or false
end

function isDir(name)
    if type(name)~="string" then return false end
    local cd = lfs.currentdir()
    local is = lfs.chdir(name) and true or false
    lfs.chdir(cd)
    return is
end

os.rename(name1, name2)会将name1重命名为name2。如果使用相同的名称,除了出现错误之外,什么也不会改变。如果一切顺利,它将返回true,否则它将返回nil和错误消息。您说您不想使用lfs。如果不使用lfs,则无法区分文件和目录,而不必尝试打开文件(这可能会稍微慢一些,但还好)。

因此,没有LuaFileSystem

-- no require("lfs")

function exists(name)
    if type(name)~="string" then return false end
    return os.rename(name,name) and true or false
end

function isFile(name)
    if type(name)~="string" then return false end
    if not exists(name) then return false end
    local f = io.open(name)
    if f then
        f:close()
        return true
    end
    return false
end

function isDir(name)
    return (exists(name) and not isFile(name))
end

看起来代码更短,但需要更长的时间......另外,打开文件是有风险的,因此您应该使用lfs。如果您不关心性能(和错误处理-.-),那么可以直接使用它。

编写愉快!


3
io.open同样适用于目录。您需要尝试读取它(f:read(1))才能实现。 - blueyed
谢谢!我不知道那个!如果文件为空(如果我添加'f:read(1)'),那也会抛出错误吗?据我所知,'f:read(0)'也没用... - tDwtp

3

这是针对Windows平台的测试。实际上,这相当容易:

local function directory_exists( sPath )
  if type( sPath ) ~= "string" then return false end

  local response = os.execute( "cd " .. sPath )
  if response == 0 then
    return true
  end
  return false
end

显然,这种方法可能不适用于其他操作系统。但对于Windows用户来说,这可能是一个解决方案 :)

当我在Linux和Windows上测试时,无论sPath是否存在,response都是nil - Alex
1
通常情况下,调用外部程序执行如此简单的任务并不被视为良好的做法,因为这往往会产生与解决的问题一样多的问题。在类Unix操作系统中,应该对 sPath 参数进行引号包裹(不确定Windows),这很难正确完成。 - Lassi

2

以下是一种简单的方法,可以检查文件夹是否存在,而不需要任何外部库依赖 :)

function directory_exists(path)
  local f  = io.popen("cd " .. path)
  local ff = f:read("*all")

  if (ff:find("ItemNotFoundException")) then
    return false
  else
    return true
  end  
end

print(directory_exists("C:\\Users"))
print(directory_exists("C:\\ThisFolder\\IsNotHere"))

如果您将上述内容复制并粘贴到Lua中,您应该会看到:
false
true

祝你好运 :)


5
这个解决方案似乎假定用户正在使用Powershell... 不过,检查cd命令的返回代码可能会起作用。 - djs
我原本期望第一个结果为真,第二个结果为假。 - RAL
@RAL 只需输入 not directory_exists("C:\\ThisFolder\\IsNotHere") - Fox

1

这个感觉很简单,我觉得没人做的原因可能是有点难以理解。

但它在我的机器上(Ubuntu focal)可以为文件和目录工作。

然而,它会说存在但被禁止的文件不存在。

对于快速脚本或少量文件:

function exists(path)
    return (io.open(path,"r") ~= nil)
end

好的实践:

function exists(path)
    local file = io.open(path,"r")
    if (file ~= nil) then
        io.close(file)
        return true
    else
        return false
    end
end

0

针对Linux用户:

function dir_exists( path )
if type( path ) ~= 'string' then
    error('input error')
    return false
end
local response = os.execute( 'cd ' .. path )
if response == nil then
    return false
end
return response
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接