Go的标准库并没有专门用来检查文件是否存在的函数(就像Python的os.path.exists)。惯用的做法是什么?


当前回答

检查一个文件是否不存在,相当于Python的if not os.path.exists(filename):

if _, err := os.Stat("/path/to/whatever"); errors.Is(err, os.ErrNotExist) {
  // path/to/whatever does not exist
}

检查一个文件是否存在,相当于Python的if os.path.exists(filename):

编辑:根据最近的评论

if _, err := os.Stat("/path/to/whatever"); err == nil {
  // path/to/whatever exists

} else if errors.Is(err, os.ErrNotExist) {
  // path/to/whatever does *not* exist

} else {
  // Schrodinger: file may or may not exist. See err for details.

  // Therefore, do *NOT* use !os.IsNotExist(err) to test for file existence


}

其他回答

    _, err := os.Stat(file)
    if err == nil {
        log.Printf("file %s exists", file)
    } else if os.IsNotExist(err) {
        log.Printf("file %s not exists", file)
    } else {
        log.Printf("file %s stat error: %v", file, err)
    }

让我们先看几个方面,golang的os包提供的两个函数都不是实用程序,而是错误检查器,我的意思是说它们只是跨平台处理错误的包装器。

基本上如果os。如果这个函数没有给出任何错误,那就意味着这个文件存在,如果它有,你需要检查它是什么类型的错误,这里有两个函数os的使用。IsNotExist和os.IsExist。

这可以理解为文件抛出错误的Stat,因为它不存在,或者它抛出错误是因为它存在,并且有一些问题。

这些函数所接受的形参是类型错误的,尽管你可以将nil传递给它,但这没有意义。

这也说明了IsExist和!IsNotExist是两个完全不同的东西。

所以现在如果你想知道一个给定的文件是否存在于go中,我想最好的方法是:

if _, err := os.Stat(path/to/file); !os.IsNotExist(err){
   //TODO
} 

其他答案忽略的是,给函数的路径实际上可能是一个目录。下面的函数确保,路径确实是一个文件。

func fileExists(filename string) bool {
    info, err := os.Stat(filename)
    if os.IsNotExist(err) {
        return false
    }
    return !info.IsDir()
}

另一件需要指出的事情是:这段代码仍然可能导致竞态条件,即在fileExists函数运行时,另一个线程或进程删除或创建指定的文件。

如果您担心这一点,可以在线程中使用锁,序列化对该函数的访问,或者在涉及多个应用程序时使用进程间信号量。如果涉及到其他应用程序,超出了您的控制范围,我想您就不走运了。

正如在其他回答中提到的,可以通过使用os.OpenFile的不同标志来构造所需的行为/错误。事实上,os。Create只是这样做的一个合理的默认值简写:

// Create creates or truncates the named file. If the file already exists,
// it is truncated. If the file does not exist, it is created with mode 0666
// (before umask). If successful, methods on the returned File can
// be used for I/O; the associated file descriptor has mode O_RDWR.
// If there is an error, it will be of type *PathError.
func Create(name string) (*File, error) {
    return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}

你应该自己结合这些标志来获得你感兴趣的行为:

// Flags to OpenFile wrapping those of the underlying system. Not all
// flags may be implemented on a given system.
const (
    // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
    O_RDONLY int = syscall.O_RDONLY // open the file read-only.
    O_WRONLY int = syscall.O_WRONLY // open the file write-only.
    O_RDWR   int = syscall.O_RDWR   // open the file read-write.
    // The remaining values may be or'ed in to control behavior.
    O_APPEND int = syscall.O_APPEND // append data to the file when writing.
    O_CREATE int = syscall.O_CREAT  // create a new file if none exists.
    O_EXCL   int = syscall.O_EXCL   // used with O_CREATE, file must not exist.
    O_SYNC   int = syscall.O_SYNC   // open for synchronous I/O.
    O_TRUNC  int = syscall.O_TRUNC  // truncate regular writable file when opened.
)

根据您选择的内容,您将得到不同的错误。

下面是一个示例,它将截断一个现有文件,或者当文件存在时失败。

openOpts := os.O_RDWR|os.O_CREATE
if truncateWhenExists {
    openOpts |= os.O_TRUNC // file will be truncated
} else {
    openOpts |= os.O_EXCL  // file must not exist
}
f, err := os.OpenFile(filePath, openOpts, 0644)
// ... do stuff

检查文件是否存在的最佳方法:

if _, err := os.Stat("/path/to/file"); err == nil || os.IsExist(err) {
    // your code here if file exists
}