Go的标准库没有专门用于检查文件是否存在的函数(如Python的os.path.exists
)。什么是惯用方式?
答案 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
golang
包os.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")
}
}
其他方式
使用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"))
}
答案 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