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

时间:2012-09-20 18:42:02

标签: file go standard-library

Go的标准库没有专门用于检查文件是否存在的函数(如Python的os.path.exists)。什么是惯用方式?

13 个答案:

答案 0 :(得分:596)

检查文件是否不存在,等同于Python的if not os.path.exists(filename)

if _, err := os.Stat("/path/to/whatever"); os.IsNotExist(err) {
  // 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 os.IsNotExist(err) {
  // 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


}

答案 1 :(得分:107)

通过gonuts邮件列表中的 Caleb Spare 回答。

  

[...]实际上并不需要经常使用os.Stat   对于需要它的情况来说足够简单。

     

[...]例如:如果要打开文件,则没有理由先检查它是否存在。检查和打开之间文件可能会消失,无论如何,无论如何,您都需要检查os.Open错误。因此,您只需在尝试后拨打os.IsNotExist(err)即可   打开文件,并在那里处理它不存在(如果需要特殊处理)。

     

[...]你根本不需要检查现有的路径(你不应该)。

     
      无论路径是否已存在,
  • os.MkdirAll都有效。 (您还需要检查该呼叫的错误。)

  •   
  • 您应该使用os.Create而不是os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)。这样,如果文件已经存在,您将收到错误。此外,没有其他制作文件的竞争条件,与预先检查存在的版本不同。

  •   

取自:https://groups.google.com/forum/#!msg/golang-nuts/Ayx-BMNdMFo/4rL8FFHr8v4J

答案 2 :(得分:24)

您应该使用os.Stat()os.IsNotExist()函数,如以下示例所示:

// Exists reports whether the named file or directory exists.
func Exists(name string) bool {
    if _, err := os.Stat(name); err != nil {
        if os.IsNotExist(err) {
            return false
        }
    }
    return true
}

该示例摘自here

答案 3 :(得分:12)

example by user11617不正确;它会报告该文件存在,即使它没有,但有一些其他类型的错误。

签名应为Exists(字符串)(bool,错误)。然后,实际上,呼叫站点并没有更好。

他写的代码更好:

func Exists(name string) bool {
    _, err := os.Stat(name)
    return !os.IsNotExist(err)
}

但我建议这样做:

func Exists(name string) (bool, error) {
  _, err := os.Stat(name)
  if os.IsNotExist(err) {
    return false, nil
  }
  return err != nil, err
}

答案 4 :(得分:9)

    _, 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)
    }

答案 5 :(得分:8)

首先要考虑的是,您很少会只想检查文件是否存在。在大多数情况下,如果文件存在,您会尝试对文件执行某些操作。在 Go 中,任何时候你试图对一个不存在的文件执行一些操作,结果应该是一个特定的错误(os.ErrNotExist),最好的做法是检查是否返回 err值(例如,调用 os.OpenFile(...) 之类的函数时)为 os.ErrNotExist

推荐的方法过去

file, err := os.OpenFile(...)
if os.IsNotExist(err) {
    // handle the case where the file doesn't exist
}

但是,自从在 Go 1.13 中添加了 errors.Is(于 2019 年末发布)后,the new recommendation is to use errors.Is

file, err := os.OpenFile(...)
if errors.Is(err, os.ErrNotExist) {
    // handle the case where the file doesn't exist
}

通常最好避免使用 os.Stat 来检查文件是否存在,然后再尝试对其进行操作,因为文件总是有可能被重命名、删除等. 在你用它做某事之前的时间窗口。

但是,如果您同意这个警告,并且您真的真的只想检查文件是否存在,然后继续使用它做一些有用的事情(作为一个人为的例子,假设您正在编写一个毫无意义的文件) CLI 工具会告诉您文件是否存在,然后退出 ¯\_(ツ)_/¯),那么推荐的方法是:

if _, err := os.Stat(filename); errors.Is(err, os.ErrNotExist) {
    // file does not exist
} else {
    // file exists
}

答案 6 :(得分:6)

功能示例:

func file_is_exists(f string) bool {
    _, err := os.Stat(f)
    if os.IsNotExist(err) {
        return false
    }
    return err == nil
}

答案 7 :(得分:5)

其他答案遗漏的是,赋予该函数的路径实际上可能是目录。以下功能可确保该路径确实是一个文件。

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

还有一点要指出:此代码仍可能导致争用情况,在fileExists函数运行时,另一个线程或进程删除或创建了指定的文件。

如果您对此感到担心,请在线程中使用锁定,序列化对此函数的访问或在涉及多个应用程序时使用进程间信号量。我想,如果涉及其他应用程序,则超出了您的控制范围。

答案 8 :(得分:3)

让我们首先看几个方面,os golangos.Stat提供的功能不是实用程序而是错误检查器,我的意思是它们只是处理错误的包装器跨平台。

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

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

这些函数所采用的参数类型为error,但您可以将nil传递给它,但它没有意义。

这也指出了IsExist is not same as !IsNotExist这一事实,它们是两种不同的东西。

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

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

答案 9 :(得分:3)

如其他答案所述,可以通过在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.
)

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

在此示例中,我希望打开一个文件进行写入,但是只有在用户说可以的情况下,我才会截断现有文件:

var f *os.File
if truncateWhenExists {
    // O_TRUNC - truncate regular writable file when opened.
    if f, err = os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
        log.Fatalln("failed to force-open file, err:", err)
    }
} else {
    // O_EXCL - used with O_CREATE, file must not exist
    if f, err = os.OpenFile(filepath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0644); err != nil {
        log.Fatalln("failed to open file, err:", err) 
   }
}

答案 10 :(得分:3)

基本上


package main

import (
    "fmt"
    "os"
)

func fileExists(path string) bool {
    _, err := os.Stat(path)
    return !os.IsNotExist(err)
}

func main() {

    var file string = "foo.txt"
    exist := fileExists(file)
    
    if exist {
        fmt.Println("file exist")
    } else {

        fmt.Println("file not exists")
    }

}

run example

其他方式

使用os.Open

package main

import (
    "fmt"
    "os"
)

func fileExists(path string) bool {
    _, err := os.Open(path) // For read access.
    return err == nil

}

func main() {

    fmt.Println(fileExists("d4d.txt"))

}


run it

答案 11 :(得分:2)

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

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

答案 12 :(得分:1)

这就是我检查文件是否存在于 .c

Go 1.16