Goの標準ライブラリには、(Pythonのようにos.path.exists
)ファイルが存在するかどうかを確認することのみを目的とした関数はありません。それを行う慣用的な方法は何ですか?
Goの標準ライブラリには、(Pythonのようにos.path.exists
)ファイルが存在するかどうかを確認することのみを目的とした関数はありません。それを行う慣用的な方法は何ですか?
回答:
ファイルが存在しないかどうかを確認するには、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
、ENOTDIRが返されることもあります。たとえば、/etc/bashrc
存在する場合は、/etc/bashrc/foobar
返されますENOTDIR
!os.IsNotExist(err)
。ファイルは存在する可能性がありますが、os.Stat
他の理由(許可、ディスクの障害など)で失敗します。err == nil
条件として使用すると、「ファイルが存在しない」などの障害が誤って分類されます。
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
次の例のように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
}
user11617の例は正しくありません。存在しない場合でもファイルが存在することを報告しますが、その他のエラーが発生しました。
署名は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
ですか?エラーがある場合、ファイルはおそらく存在しませんか?
他の答えが逃したのは、関数に与えられたパスが実際にはディレクトリである可能性があるということです。次の関数は、パスが実際にファイルであることを確認します。
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
指摘すべきもう1つのこと:このコードは、fileExists関数の実行中に、別のスレッドまたはプロセスが指定されたファイルを削除または作成するという競合状態を引き起こす可能性があります。
これが心配な場合は、スレッドでロックを使用するか、この関数へのアクセスをシリアル化するか、複数のアプリケーションが関係する場合はプロセス間セマフォを使用してください。他のアプリケーションが関与している場合、あなたのコントロールの外では、あなたは運が悪いと思います。
関数の例:
func file_is_exists(f string) bool {
_, err := os.Stat(f)
if os.IsNotExist(err) {
return false
}
return err == nil
}
最初にいくつかの側面を見てみましょう。packageが提供する関数はどちらもユーティリティos
でgolang
はなくエラーチェッカーです。つまり、クロスプラットフォームでエラーを処理するためのラッパーにすぎないということです。
したがって、基本的にos.Stat
この関数でエラーが発生しない場合、つまりファイルが存在することを意味し、エラーの種類を確認する必要がある場合、これら2つの関数os.IsNotExist
とを使用しますos.IsExist
。
これStat
は、ファイルが存在しないためにエラーがスローされている、または存在していて何らかの問題があるためにエラーがスローされていると理解できます。
これらの関数がとるパラメーターは型error
ですが、渡すことはできるかもしれませんがnil
、意味がありません。
これはIsExist is not same as !IsNotExist
、2つの方法が異なるという事実も示しています。
したがって、特定のファイルがgoに存在するかどうかを知りたい場合は、次の方法が最適です。
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)
}
}