Goにファイルが存在するかどうかを確認する方法


435

Goの標準ライブラリには、(Pythonのようにos.path.exists)ファイルが存在するかどうかを確認することのみを目的とした関数はありません。それを行う慣用的な方法は何ですか?


本当にわかりません。同時に、標準関数はないと言って、標準関数で答えを書いた。何が欠けていますか?少なくとも質問は修正されるべきではありませんか?
DenysSéguret2012

@dystroy-質問を修正しました。
Sridhar Ratnakumar 2012

11
ファイルの存在を問い合わせないようにしてください。回答の際どい性質のB / c、得られた情報は、要求された時間に存在したファイルの上に実際には何も有用ではないことを示しています-しかし、それはもう存在しない可能性があります。推奨される方法は、単にファイルを開いて、それが失敗するかどうかを確認することです。
zzzz


2
@zzzz(私はそれが何年も前であることを知っています、このコメントは新しい読者のためです)私は一般的なケースで同意します。しかし、私のアプリは、一部のファイルパスを初期化データとして使用するサードパーティライブラリをロードしますが、ファイルが存在しない場合はセグメンテーション違反になります。私のコードはファイルの内容を読み取ったり、ファイルに直接書き込んだりする必要がないため、致命的なクラッシュなしにエラーを報告できるように、ファイルを開こうとせずにファイルが存在するかどうかを確認するには、これは有効なシナリオだと思います。
セルジオアコスタ

回答:


690

ファイルが存在しないかどうかを確認するには、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


}

3
場合によってはNOTEXIST、ENOTDIRが返されることもあります。たとえば、/etc/bashrc存在する場合は、/etc/bashrc/foobar返されますENOTDIR
Lidaobing

43
2番目のスニペットはもっと微妙に間違っています。状態はでなければなりません!os.IsNotExist(err)。ファイルは存在する可能性がありますが、os.Stat他の理由(許可、ディスクの障害など)で失敗します。err == nil条件として使用すると、「ファイルが存在しない」などの障害が誤って分類されます。
sqweek 2015

9
ファイルが存在するかどうかを確認するのは間違っています。ファイルが存在する場合、errはnilです
tangxinfa

1
〜拡大することを確認してくださいまたはそうでなければfalseを返します... stackoverflow.com/questions/17609732/...
マルチェロドゥ販売

場合によってはos.IsExist()を使用できます。!os.IsNotExistant()を実行するときに二重否定を行う代わりに、より慣用的に使用できます
Ariel Monaco

126

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


30

次の例のように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
}

例はここから抽出されます


12
注意:stackoverflow.com/a/22467409/712014が指摘しているように、このコードは、たとえStat()が権限拒否を返した場合など、ファイルが存在しない場合でもtrueを返します。
Michael

19

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
}

7
例5とは何ですか?具体的に教えてください。
xlm 2014年

1
2番目の例では、複数の戻り値を分解する必要があります。例:_、err:= os.Stat(name)
David Duncan

6
なぜerr != nil代わりに戻るのerr == nilですか?エラーがある場合、ファイルはおそらく存在しませんか?
idbrii

14

他の答えが逃したのは、関数に与えられたパスが実際にはディレクトリである可能性があるということです。次の関数は、パスが実際にファイルであることを確認します。

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

指摘すべきもう1つのこと:このコードは、fileExists関数の実行中に、別のスレッドまたはプロセスが指定されたファイルを削除または作成するという競合状態を引き起こす可能性があります。

これが心配な場合は、スレッドでロックを使用するか、この関数へのアクセスをシリアル化するか、複数のアプリケーションが関係する場合はプロセス間セマフォを使用してください。他のアプリケーションが関与している場合、あなたのコントロールの外では、あなたは運が悪いと思います。


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

7

関数の例:

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

1
冗長な場合はありませんか?
Ilia Choly

6

最初にいくつかの側面を見てみましょう。packageが提供する関数はどちらもユーティリティosgolangはなくエラーチェッカーです。つまり、クロスプラットフォームでエラーを処理するためのラッパーにすぎないということです。

したがって、基本的に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
} 

1

他の回答で述べたように、で異なるフラグを使用することにより、必要な動作/エラーを構築でき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) 
   }
}

0

ファイルが存在するかどうかを確認する最良の方法:

if _, err := os.Stat("/path/to/file"); err == nil || os.IsExist(err) {
    // your code here if file exists
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.