Go'da bir dosyanın olup olmadığını nasıl kontrol edebilirim?


436

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 ?


Gerçekten anlamıyorum. Aynı anda standart bir fonksiyon olmadığını söylüyorsunuz ve standart fonksiyonla bir cevap yazıyorsunuz. Neyi kaçırıyorum ? En azından soru düzeltilmemeli mi?
Denys Séguret

@dystroy - soruyu düzeltti.
Sridhar Ratnakumar

11
Dosya varlığını sorgulamaktan kaçınmalısınız. B / c cevabın açık saçık doğası, elde edilen bilgiler aslında dosyanın üzerinde yararlı hiçbir şey sorulan süre içinde var diyor - ama artık olmayabilir. Önerilen yol sadece bir dosyayı açmak ve başarısız olup olmadığını kontrol etmektir.
zzzz

2
Bu zaten burada
Sergey Koulikov

2
@zzzz (Yıllar geçtiğini biliyorum, bu yorum yeni okuyucular için) Genel davada katılıyorum. Ancak uygulamam, başlatma dosyası olarak bazı dosya yollarını alan ancak dosya yoksa segfaults alan bir üçüncü taraf kitaplığı yükler. Kodum dosya içeriğini okumak veya doğrudan dosyaya yazması gerekmediğinden, bu dosyanın ölümcül bir çökme olmadan hatayı bildirmek için açmaya çalışırken dosyanın var olup olmadığını kontrol etmek için geçerli bir senaryo olduğunu düşünüyorum.
Sergio Acosta

Yanıtlar:


693

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


}

3
bazen yerine ENOTDIR dönmek NOTEXISTdurumunda, örneğin, /etc/bashrcexist, /etc/bashrc/foobardönecektirENOTDIR
lidaobing

43
İkinci pasaj daha açık bir şekilde yanlıştır; durum olmalı !os.IsNotExist(err). Dosya var olabilir ancak os.Statbaşka nedenlerle başarısız olabilir (örn. İzin, başarısız disk). Kullanılması err == nildurum yanlış "dosya yok" gibi arızaları sınıflandırılıyor olarak.
sqweek

9
Dosyanın yanlış olup olmadığını kontrol etmek için: dosya varsa err nil
tangxinfa

1
Genişlettiğinizden emin olun ~ yoksa başka şekilde yanlış döndürür ... stackoverflow.com/questions/17609732/…
Marcello de Sales

Davaya bağlı olarak os.IsExist () kullanabilirsiniz, yaparken o çift kişilik bir olumsuzlama yapmak yerine daha idiyomatik olabilir! Os.IsNotExistant ()
Ariel Monaco

126

Tarafından cevap Caleb Yedek gönderilmiş gonuts posta listesi.

[...] Aslında çok sık ihtiyaç duyulmuyor ve [...] kullanılması os.Statgereken 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.Openhatayı ne olursa olsun kontrol etmeniz gerekir . Yani os.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.MkdirAllyollar zaten mevcut olsun veya olmasın çalışır. (Ayrıca bu çağrıdaki hatayı kontrol etmeniz gerekir.)

  • Kullanmak yerine os.Createkullanmalısınız os.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


31

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 .


12
Dikkat: stackoverflow.com/a/22467409/712014'te belirtildiği gibi , bu kod, dosya olmasa bile, örneğin Stat () izni reddedildiğinde geri döner.
Michael

19

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
}

7
Örnek 5 nedir? Lütfen spesifik olabilir misiniz?
xlm

1
İkinci örneğinizin birden fazla dönüş değerini imha etmesi gerekiyor - örneğin _, err: = os.Stat (isim)
David Duncan

6
Neden err != nilyerine geri dönelim err == nil? Bir hata varsa, dosya muhtemelen mevcut değil mi?
idbrii

14

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.


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

İşlev örneği:

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

1
Fazlalık değil mi?
Ilia Choly

6

Önce birkaç yöne bakalım, hem ospaket tarafından sağlanan işlev golangyardı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.Statbu 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.IsNotExistve 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 !IsNotExistiki 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
} 

1

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.Createbunu 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) 
   }
}

0

Dosyanın var olup olmadığını kontrol etmenin en iyi yolu:

if _, err := os.Stat("/path/to/file"); err == nil || os.IsExist(err) {
    // your code here if file exists
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.