Go'nun standart kitaplığının yalnızca bir dosyanın var olup olmadığını kontrol etmek amacıyla (Python'lar gibi os.path.exists
) bir işlevi yoktur . Bunu yapmanın deyimsel yolu nedir ?
Go'nun standart kitaplığının yalnızca bir dosyanın var olup olmadığını kontrol etmek amacıyla (Python'lar gibi os.path.exists
) bir işlevi yoktur . Bunu yapmanın deyimsel yolu nedir ?
Yanıtlar:
Bir dosyanın bulunup bulunmadığını kontrol etmek için Python'lara eşdeğerdir if not os.path.exists(filename)
:
if _, err := os.Stat("/path/to/whatever"); os.IsNotExist(err) {
// path/to/whatever does not exist
}
Bir dosyanın var olup olmadığını kontrol etmek için Python'lara eşdeğerdir if os.path.exists(filename)
:
Düzenlendi: son yorumlar başına
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
durumunda, örneğin, /etc/bashrc
exist, /etc/bashrc/foobar
dönecektirENOTDIR
!os.IsNotExist(err)
. Dosya var olabilir ancak os.Stat
başka nedenlerle başarısız olabilir (örn. İzin, başarısız disk). Kullanılması err == nil
durum yanlış "dosya yok" gibi arızaları sınıflandırılıyor olarak.
Tarafından cevap Caleb Yedek gönderilmiş gonuts posta listesi.
[...] Aslında çok sık ihtiyaç duyulmuyor ve [...] kullanılması
os.Stat
gereken durumlar için yeterince kolay.[...] Örneğin: dosyayı açacaksanız, önce var olup olmadığını kontrol etmek için bir neden yoktur. Dosya kontrol etme ve açma arasında kaybolabilir ve yine de
os.Open
hatayı ne olursa olsun kontrol etmeniz gerekir . Yanios.IsNotExist(err)
dosyayı açmayı denedikten sonra arayın ve orada bulunmamasıyla ilgilenin (bu özel işlem gerektiriyorsa).[...] Mevcut yolları kontrol etmenize gerek yok (ve yapmamalısınız).
os.MkdirAll
yollar zaten mevcut olsun veya olmasın çalışır. (Ayrıca bu çağrıdaki hatayı kontrol etmeniz gerekir.)Kullanmak yerine
os.Create
kullanmalısınızos.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
. Bu şekilde dosya zaten varsa bir hata alırsınız. Ayrıca, önceden varlığını kontrol eden sürümünüzün aksine, dosyayı başka bir şeyle yapan bir yarış durumu yoktur.
Alındığı yer: https://groups.google.com/forum/#!msg/golang-nuts/Ayx-BMNdMFo/4rL8FFHr8v4J
os.Stat()
Ve os.IsNotExist()
işlevlerini aşağıdaki örnekte olduğu gibi kullanmalısınız :
// 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
}
Örnek buradan alınmıştır .
User11617 göre örneğin yanlış; dosyanın bulunmadığı durumlarda bile var olduğunu bildirecektir, ancak başka bir tür hata vardı.
İmza Var (dize) (bool, hata) olmalıdır. Ve sonra, olduğu gibi, çağrı siteleri daha iyi değildir.
Yazdığı kod daha iyi olurdu:
func Exists(name string) bool {
_, err := os.Stat(name)
return !os.IsNotExist(err)
}
Ama bunun yerine şunu öneririm:
func Exists(name string) (bool, error) {
_, err := os.Stat(name)
if os.IsNotExist(err) {
return false, nil
}
return err != nil, err
}
err != nil
yerine geri dönelim err == nil
? Bir hata varsa, dosya muhtemelen mevcut değil mi?
Diğer cevapların kaçırdığı şey, işleve verilen yolun aslında bir dizin olabileceğidir. Aşağıdaki işlev, yolun gerçekten bir dosya olmasını sağlar.
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
Dikkat çekilmesi gereken başka bir şey: Bu kod, fileExists işlevi çalışırken başka bir iş parçacığının veya işlemin belirtilen dosyayı sildiği veya oluşturduğu bir yarış durumuna neden olabilir.
Bu konuda endişeleriniz varsa, iş parçacıklarınızda bir kilit kullanın, bu işleve erişimi serileştirin veya birden çok uygulama söz konusu olduğunda süreçler arası bir semafor kullanın. Başka uygulamalar söz konusuysa, sizin kontrolünüz dışında, şansınız yok sanırım.
İşlev örneği:
func file_is_exists(f string) bool {
_, err := os.Stat(f)
if os.IsNotExist(err) {
return false
}
return err == nil
}
Önce birkaç yöne bakalım, hem os
paket tarafından sağlanan işlev golang
yardımcı programlar değil, hata denetleyicileri, bununla ne demek istediğim sadece çapraz platformdaki hataları işlemek için bir sarıcı.
Temel olarak os.Stat
bu işlev herhangi bir hata vermezse, dosyanın ne tür bir hata olduğunu kontrol etmeniz gerektiğinde var olduğu anlamına gelir, işte bu iki işlevin os.IsNotExist
ve geliyor os.IsExist
.
Bu şu şekilde anlaşılabilir: Stat
, dosya atma hatası çünkü mevcut değildir veya var olduğu için hata atmadır ve onunla ilgili bir sorun vardır.
Bu işlevlerin aldığı parametre türdür error
, ancak geçebilmeniz mümkünnil
, ancak mantıklı olmaz.
Bu aynı zamanda IsExist is not same as !IsNotExist
iki farklı şey olduklarına işaret ediyor .
Şimdi verilen bir dosyanın hareket halinde olup olmadığını bilmek istiyorsanız, en iyi yolu tercih ederim:
if _, err := os.Stat(path/to/file); !os.IsNotExist(err){
//TODO
}
Diğer cevaplarda belirtildiği gibi, farklı bayrakları kullanmak için gerekli davranış / hataları oluşturmak mümkündür os.OpenFile
. Aslında, os.Create
bunu yapmak için sadece mantıklı bir varsayılan kısayol:
// 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)
}
İlgilendiğiniz davranışı elde etmek için bu bayrakları kendiniz birleştirmelisiniz:
// 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.
)
Ne seçtiğinize bağlı olarak, farklı hatalar alırsınız.
İşte bir dosyayı yazmak için açmak istediğim bir örnek, ancak mevcut bir dosyayı yalnızca kullanıcı tamam olduğunu söylerse keserim:
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)
}
}