Go的标准库没有专门用于检查文件是否存在的函数(如Python的os.path.exists
)。什么是惯用的方式做到这一点?
Go的标准库没有专门用于检查文件是否存在的函数(如Python的os.path.exists
)。什么是惯用的方式做到这一点?
Answers:
要检查文件是否不存在,等同于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
}
NOTEXIST
,例如,如果/etc/bashrc
存在,/etc/bashrc/foobar
遗嘱将返回ENOTDIR
!os.IsNotExist(err)
。该文件可能存在,但os.Stat
由于其他原因而失败(例如,权限,磁盘故障)。err == nil
作为条件使用错误地将失败分类为“文件不存在”。
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
您应该在以下示例中使用os.Stat()
and 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
}
该示例从此处提取。
user11617的示例不正确;它将报告该文件存在,即使在不存在的情况下,也存在其他错误。
签名应为Exists(string)(布尔,错误)。然后,碰巧的是,呼叫站点并没有更好。
他编写的代码最好是:
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
?如果有错误,则文件可能不存在?
其他答案遗漏的是,赋予该函数的路径实际上可能是目录。跟随功能可确保该路径确实是一个文件。
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
需要指出的另一点是:该代码仍可能导致争用情况,在fileExists函数运行时,另一个线程或进程删除或创建了指定的文件。
如果您对此感到担心,请在线程中使用锁,序列化对此函数的访问,或者如果涉及多个应用程序,请使用进程间信号灯。我想,如果涉及其他应用程序,那么您将无法控制。
首先让我们看几个方面,的os
软件包提供的功能golang
不是实用程序而是错误检查器,我的意思是,它们只是包装跨平台错误的包装器。
因此,基本上,os.Stat
如果该函数没有给出任何错误,则意味着如果该文件存在,则需要检查它是什么类型的错误,这时将使用这两个函数os.IsNotExist
和os.IsExist
。
这可以理解为Stat
文件抛出错误的原因,因为它不存在,或者是因为它存在而引发错误,并且存在一些问题。
这些函数采用的参数的类型为error
,尽管您可以传递nil
给它,但这没有任何意义。
这也指出了一个事实IsExist is not same as !IsNotExist
,它们是两种不同的方式。
因此,现在如果您想知道给定文件是否存在,我希望最好的方法是:
if _, err := os.Stat(path/to/file); !os.IsNotExist(err){
//TODO
}
如其他答案中所述,可以通过使用带有的不同标志来构造所需的行为/错误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)
}
}