Die Standardbibliothek von Go verfügt nicht über eine Funktion, mit der ausschließlich überprüft werden soll, ob eine Datei vorhanden ist oder nicht (wie bei Python os.path.exists
). Was ist der idiomatische Weg, um es zu tun?
Die Standardbibliothek von Go verfügt nicht über eine Funktion, mit der ausschließlich überprüft werden soll, ob eine Datei vorhanden ist oder nicht (wie bei Python os.path.exists
). Was ist der idiomatische Weg, um es zu tun?
Antworten:
Um zu überprüfen, ob eine Datei nicht vorhanden ist, entspricht Python if not os.path.exists(filename)
:
if _, err := os.Stat("/path/to/whatever"); os.IsNotExist(err) {
// path/to/whatever does not exist
}
So überprüfen Sie, ob eine Datei vorhanden ist, die Python entspricht if os.path.exists(filename)
:
Bearbeitet: gemäß den letzten Kommentaren
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
zum Beispiel, falls /etc/bashrc
vorhanden, das /etc/bashrc/foobar
wird zurückkehrenENOTDIR
!os.IsNotExist(err)
. Es ist möglich, dass die Datei vorhanden ist, aber os.Stat
aus anderen Gründen fehlschlägt (z. B. Berechtigung, fehlerhafte Festplatte). Wenn Sie err == nil
als Bedingung verwenden, werden Fehler fälschlicherweise als "Die Datei existiert nicht" kategorisiert.
Antwort von Caleb Spare in der Gonuts- Mailingliste.
[...] Es wird eigentlich nicht sehr oft benötigt und [...] die Verwendung
os.Stat
ist für die Fälle, in denen es erforderlich ist, einfach genug.[...] Zum Beispiel: Wenn Sie die Datei öffnen möchten, gibt es keinen Grund, zuerst zu prüfen, ob sie vorhanden ist. Die Datei kann zwischen dem Überprüfen und Öffnen verschwinden, und Sie müssen den
os.Open
Fehler trotzdem überprüfen . Sie rufen einfach an,os.IsNotExist(err)
nachdem Sie versucht haben, die Datei zu öffnen, und kümmern sich dort um ihre Nichtexistenz (wenn dies eine besondere Behandlung erfordert).[...] Sie müssen nicht nach vorhandenen Pfaden suchen (und sollten dies auch nicht tun).
os.MkdirAll
funktioniert unabhängig davon, ob die Pfade bereits vorhanden sind oder nicht. (Außerdem müssen Sie den Fehler dieses Aufrufs überprüfen.)Anstatt zu verwenden
os.Create
, sollten Sie verwendenos.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
. Auf diese Weise erhalten Sie eine Fehlermeldung, wenn die Datei bereits vorhanden ist. Dies hat auch keine Race-Bedingung, bei der die Datei von etwas anderem erstellt wird, im Gegensatz zu Ihrer Version, die zuvor die Existenz überprüft.
Entnommen aus: https://groups.google.com/forum/#!msg/golang-nuts/Ayx-BMNdMFo/4rL8FFHr8v4J
Sie sollten die Funktionen os.Stat()
und os.IsNotExist()
wie im folgenden Beispiel verwenden:
// 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
}
Das Beispiel wird aus extrahiert hier .
Das Beispiel von user11617 ist falsch; Es wird gemeldet, dass die Datei auch dann vorhanden ist, wenn dies nicht der Fall ist, aber ein anderer Fehler aufgetreten ist.
Die Signatur sollte Exists (Zeichenfolge) sein (Bool, Fehler). Und dann sind die Anrufseiten nicht besser.
Der Code, den er schrieb, wäre besser als:
func Exists(name string) bool {
_, err := os.Stat(name)
return !os.IsNotExist(err)
}
Aber ich schlage stattdessen Folgendes vor:
func Exists(name string) (bool, error) {
_, err := os.Stat(name)
if os.IsNotExist(err) {
return false, nil
}
return err != nil, err
}
err != nil
statt err == nil
? Wenn es einen Fehler gibt, existiert die Datei wahrscheinlich nicht?
Was andere Antworten übersehen haben, ist, dass der Pfad, der der Funktion gegeben wird, tatsächlich ein Verzeichnis sein kann. Die folgende Funktion stellt sicher, dass der Pfad wirklich eine Datei ist.
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
Noch etwas zu beachten: Dieser Code kann immer noch zu einer Race-Bedingung führen, bei der ein anderer Thread oder Prozess die angegebene Datei löscht oder erstellt, während die Funktion fileExists ausgeführt wird.
Wenn Sie sich darüber Sorgen machen, verwenden Sie eine Sperre in Ihren Threads, serialisieren Sie den Zugriff auf diese Funktion oder verwenden Sie ein prozessübergreifendes Semaphor, wenn mehrere Anwendungen beteiligt sind. Wenn andere Anwendungen beteiligt sind, die außerhalb Ihrer Kontrolle liegen, haben Sie vermutlich kein Glück.
Das Funktionsbeispiel:
func file_is_exists(f string) bool {
_, err := os.Stat(f)
if os.IsNotExist(err) {
return false
}
return err == nil
}
Schauen wir uns zunächst einige Aspekte an. Beide Funktionen des os
Pakets golang
sind keine Dienstprogramme, sondern Fehlerprüfer. Damit meine ich, dass sie nur ein Wrapper sind, um Fehler auf plattformübergreifenden Fehlern zu behandeln.
Also im Grunde , wenn , os.Stat
wenn diese Funktion nicht einen Fehler nicht geben , dass die Datei bedeutet , vorhanden ist, wenn es tut müssen Sie überprüfen , was es Art von Fehler ist, hier die Verwendung dieser beiden Funktion kommt os.IsNotExist
und os.IsExist
.
Dies kann als Stat
Fehler beim Auslösen von Dateien verstanden werden, weil er nicht vorhanden ist, oder als Fehler beim Auslösen, weil er vorhanden ist und ein Problem damit vorliegt.
Der Parameter, den diese Funktionen annehmen, ist vom Typ error
, obwohl Sie ihn möglicherweise übergeben können, nil
aber er macht keinen Sinn.
Dies weist auch auf die Tatsache hin, dass IsExist is not same as !IsNotExist
es sich um zwei verschiedene Dinge handelt.
Wenn Sie nun wissen möchten, ob eine bestimmte Datei in go vorhanden ist, würde ich den besten Weg bevorzugen:
if _, err := os.Stat(path/to/file); !os.IsNotExist(err){
//TODO
}
Wie in anderen Antworten erwähnt, ist es möglich, das erforderliche Verhalten / die erforderlichen Fehler aus der Verwendung verschiedener Flags mit zu konstruieren os.OpenFile
. In der Tat os.Create
ist nur eine sinnvolle Standardeinstellung dafür:
// 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)
}
Sie sollten diese Flags selbst kombinieren, um das Verhalten zu erhalten, an dem Sie interessiert sind:
// 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.
)
Je nachdem, was Sie auswählen, werden unterschiedliche Fehler angezeigt.
Hier ist ein Beispiel, in dem ich eine Datei zum Schreiben öffnen möchte, eine vorhandene Datei jedoch nur abschneide, wenn der Benutzer angegeben hat, dass dies in Ordnung ist:
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)
}
}