Go的标准库没有专门用于检查文件是否存在的函数(例如Python的os.path.exists
)。那么,什么是惯用的方法?
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
}
ENOTDIR
而不是NOTEXIST
,例如,如果/etc/bashrc
存在,那么/etc/bashrc/foobar
将返回ENOTDIR
。 - lidaobing!os.IsNotExist(err)
。文件可能存在但是os.Stat
因为其他原因(例如权限、磁盘故障)而失败。使用err == nil
作为条件会错误地将这种失败归类为“文件不存在”。 - sqweekerrors.Is(err, os.ErrNotExist)
:https://github.com/golang/go/blob/master/src/os/error.go#L90-L91 - Pal Kerecsenyi在gonuts邮件列表中,Caleb Spare的回答如下:
[...] 实际上并不经常需要检查路径是否存在,使用
os.Stat
对于需要检查的情况来说已经足够简单了。[...] 例如:如果您要打开文件,则没有理由先检查其是否存在。文件可能会在检查和打开之间消失,而无论如何,您都需要在尝试打开文件后检查
os.Open
错误。因此,您只需在尝试打开文件后调用os.IsNotExist(err)
,并在那里处理它的不存在(如果需要进行特殊处理)。[...] 您根本不需要检查路径是否存在(也不应该检查)。
os.MkdirAll
无论路径是否已经存在都可以工作。(还需要检查该调用的错误。)您应该使用
os.OpenFile(path,os.O_RDWR | os.O_CREATE | os.O_EXCL,0666)
,而不是使用os.Create
。这样,如果文件已经存在,您将收到一个错误。与您的版本不同,这种方式没有竞争条件阻碍其他东西创建文件。
引用自:https://groups.google.com/forum/#!msg/golang-nuts/Ayx-BMNdMFo/4rL8FFHr8v4J
os.O_EXCL
)方面遇到了很多麻烦,因为我总是记不清这些标志的含义。我原本以为os.O_CREATE
已经暗示了文件必须被创建并且在此之前不存在。 - natiiixos.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(在2019年末发布)中添加了errors.Is
,新的建议是使用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
}
os.Stat
方法:os.Stat
返回info,err
,如果err
为nil,则info
是一个FileInfo对象,您可以使用它来确定存在的东西是文件还是目录。有关更多详细信息,请参见此其他答案。 - Dave Yarwoodos.Stat()
和 os.IsNotExist()
函数,就像下面的例子一样:func Exists(name string) (bool, error) {
_, err := os.Stat(name)
if err == nil {
return true, nil
}
if errors.Is(err, os.ErrNotExist) {
return false, nil
}
return false, err
}
编辑1:修复了在某些情况下返回true的问题。
编辑2:切换到使用errors.Is()而不是os.IsNotExist(),许多人认为这是最佳实践和这里。
其他答案中没有提到的是,传递给函数的路径实际上可能是一个目录。下面的函数确保该路径确实是一个文件。
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
需要指出的另一件事是:这段代码仍然可能导致竞态条件,即在fileExists函数运行时,另一个线程或进程删除或创建了指定的文件。
如果你担心这个问题,在你的线程中使用锁,序列化访问此函数,或者如果涉及多个应用程序,则使用进程间信号量。如果其他应用程序超出你的控制范围,那就没办法了。
return !info.IsDir()
时 info
可能为空。 - igonejack签名应为Exists(string) (bool, error)。然后,正如它所发生的那样,调用方也无法更好地处理。
他编写的代码应该改为:
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
}
err != nil
而不是 err == nil
?如果有错误,那么文件可能不存在? - idbrii _, 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)
}
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"))
}
检查文件是否存在的最佳方法:
if _, err := os.Stat("/path/to/file"); err == nil || os.IsExist(err) {
// your code here if file exists
}
以下是一个函数示例:
func file_is_exists(f string) bool {
_, err := os.Stat(f)
if os.IsNotExist(err) {
return false
}
return err == nil
}