如何判断文件夹是否存在且可写?

时间:2013-11-17 02:05:56

标签: go directory

我希望func FolderExists(path string) bool能够判断文件夹是否存在且可写。我来到这里:

func FolderExists(path string) bool {
    info, err := os.Stat(path)
    return os.IsExist(err) && info.Mode().IsDir() && info.Mode().???
}

如何判断此文件夹是否可写?我不能简单地检查filemode权限(例如0200用于用户写入权限),因为那时我必须检查文件的所有者。在Go中有直接的方法吗?

对于那些拥有UNIX背景的人来说,寻找相当于非常简单的东西:

if [ -d "$n" && -w "$n" ] ; then ... fi

3 个答案:

答案 0 :(得分:8)

如果您正在为Unix-y操作系统编写代码,则可以将unix.Access(path string, mode uint32) error与常量unix.W_OK一起用作mode

正如kostix所说,您仍然需要在访问目录时检查错误(例如,当您创建或删除文件时)。您的检查可能已删除该目录,或者权限可能已更改,或者您可能会收到完全无关的错误。

(感谢用户fxxn指出自2013年原始答案以来情况有所改善,即使用syscall.Access并从W_OK中提取unistd.h常量。)< / p>

这是检查存在和访问的代码,它可以在Linux上获得预期的结果:

package main

import (
    "fmt"
    "golang.org/x/sys/unix"
)

func writable(path string) bool {
    return unix.Access(path, unix.W_OK) == nil
}

func main() {
    fmt.Println("/etc writable?", writable("/etc"))
    fmt.Println("/tmp writable?", writable("/tmp"))
}

答案 1 :(得分:2)

没有与平台无关的方法来实现这一点,因为在Windows上无法检查用户是否无法创建目录。因此,我们将针对Windows和非Windows系统以不同方式实现它,然后使用Golang的build constraints根据操作系统有条件地编译文件。

在目录file-perm下创建3个.go文件,如图所示 -

file-perm /
    file-perm.go
    is-writable.go
    is-writable_windows.go

文件:file-perm.go

package main

import (
    "fmt"
)

func main() {
    path := "/tmp/xyz"

    fmt.Println(IsWritable(path))
}

档案:is-writable.go

这构建在除Windows之外的所有平台上,因为Windows上没有syscall.Stat_t。请注意,构建约束 // + build!windows

后需要有一个空行
// +build !windows

package main

import (
    "fmt"
    "os"
    "syscall"
)

func IsWritable(path string) (isWritable bool, err error) {
    isWritable = false
    info, err := os.Stat(path)
    if err != nil {
        fmt.Println("Path doesn't exist")
        return
    }

    err = nil
    if !info.IsDir() {
        fmt.Println("Path isn't a directory")
        return
    }

    // Check if the user bit is enabled in file permission
    if info.Mode().Perm() & (1 << (uint(7))) == 0 {
        fmt.Println("Write permission bit is not set on this file for user")
        return
    }

    var stat syscall.Stat_t
    if err = syscall.Stat(path, &stat); err != nil {
        fmt.Println("Unable to get stat")
        return
    }

    err = nil
    if uint32(os.Geteuid()) != stat.Uid {
        isWritable = false
        fmt.Println("User doesn't have permission to write to this directory")
        return
    }

    isWritable = true
    return
}

档案:is-writable_windows.go

由于文件名中的 _windows.go 后缀,此文件仅在Windows上构建。有关详细信息,请参阅https://golang.org/pkg/go/build/

package main

import (
    "fmt"
    "os"
)

func IsWritable(path string) (isWritable bool, err error) {
    isWritable = false
    info, err := os.Stat(path)
    if err != nil {
        fmt.Println("Path doesn't exist")
        return
    }

    err = nil
    if !info.IsDir() {
        fmt.Println("Path isn't a directory")
        return
    }

    // Check if the user bit is enabled in file permission
    if info.Mode().Perm()&(1<<(uint(7))) == 0 {
        fmt.Println("Write permission bit is not set on this file for user")
        return
    }

    isWritable = true
    return
}
  

现在,你必须在file-perm目录中使用 go build然后运行   可执行文件。请注意,它不适用于go run。

答案 2 :(得分:0)

我的回答不会直接回答你的问题,但仍然......

简而言之:不要那样做(除非你写的东西是嵌入的)。说明:文件系统是完全并发的,因此它们本身就是竞争条件的主题。简单来说,一个序列

  1. 检查文件是否存在。
  2. 如果是,请阅读。
  3. 不能在现实世界中工作,因为文件完全能够在(1)和(2)之间消失,因为其他一些进程会删除它。

    因此,编写上述序列的唯一真正方法是删除(1)并准备处理(2)中的文件打开错误。

    回到你的问题,唯一合理的方法是尝试在目标目录中创建一个文件,并准备好处理由于目录不可写而导致的错误。此外,Go的错误处理方法专门针对此类(现实世界)情况而定制。