Şu anda çalışan dosyanın dizini nasıl alınır?


239

Nodejs olarak kullandığım __dirname . Bunun Golang'daki karşılığı nedir?

Bu makaleyi buldum ve buldum http://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/ . Aşağıdaki kodu kullandığı yerde

_, filename, _, _ := runtime.Caller(1)
f, err := os.Open(path.Join(path.Dir(filename), "data.csv"))

Ama Golang'da yapmanın doğru yolu mu yoksa deyimsel yolu mu?


Tekrar os.open aday olmamaya (dosya konumu :) çalışırken değiştirilemez) ve yine her defasında kod çalışır bu sorunuz için bir yanıt değil ama bir global var yolunu önbelleğe
oguzalb

Sen geçmelidir 0değil, 1hiç, runtime.Caller().
fiatjaf

4
runtime.Caller(0)gibi kaynak dosyanın yolunu verecektir $GOPATH/src/packagename/main.go. Bu iş parçacığındaki diğer yanıtlar, yürütülebilir dosyanın (like $GOPATH/bin/packagename) yolunu döndürmeye çalışıyor .
fiatjaf

Programın bir dosyadan çalıştığını varsayıyorsunuz ...
Flimzy

Yanıtlar:


221

Bunu yapmalı:

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
)

func main() {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
            log.Fatal(err)
    }
    fmt.Println(dir)
}

2
Burada bir hata olması mümkün müdür? Eğer öyleyse, hata ne olurdu, sadece meraktan mı?
Jeff Escalante

4
Benim için çalışmıyor play.golang.org/p/c8fe-Zm_bH - os.Args [0] mutlaka abs yolu içermiyor.
zupa

5
Aslında os.Args [0] abs yolunu içermese bile çalışır. Oyun alanının sonucunun beklediğiniz gibi olmaması, kum havuzunun içinde olmasıdır.
Gustavo Niemeyer

37
Bu güvenilir bir yol değildir , osext kullanımı ile ilgili cevaba bakın, çünkü bu, çeşitli işletim sistemlerindeki tüm müşterilerimizle çalışan bir uygulamadır. Bu yöntemi kullanarak kod uygulamıştı ama çok güvenilir gibi görünmüyor ve birçok kullanıcı bu yöntem çalıştırılabilir için yanlış yolu seçerek kaynaklanan hatalardan şikayetçi.
JD D

5
Windows'da Go 1.6 kullanarak emrah ile aynı sonucu aldım (kaynak dosya klasörü yerine temp klasörünün yolu var). Herhangi bir harici bağımlılık kullanmadan kaynak dosyanızın klasörünün yolunu bulmak için, OP kodunun değiştirilmiş bir sürümünü kullanın: _, currentFilePath, _, _ := runtime.Caller(0) dirpath := path.Dir(currentFilePath)( runtime.Caller(0)bunun yerine not edin runtime.Caller(1))
TanguyP

295

EDIT: Go 1.8 itibariyle (Şubat 2017'de piyasaya sürüldü) bunu yapmanın önerilen yolu şudur os.Executable:

func Executable() (string, error)

Yürütülebilir dosya, geçerli işlemi başlatan yürütülebilir dosyanın yol adını döndürür. Yolun hala doğru yürütülebilir dosyayı işaret ettiğinin garantisi yoktur. İşletim sistemine bağlı olarak işlemi başlatmak için bir sembolik bağlantı kullanılmışsa, sonuç sembolik bağlantı veya işaret ettiği yol olabilir. Kararlı bir sonuç gerekiyorsa, path / filepath.EvalSymlinks yardımcı olabilir.

Sadece çalıştırılabilir dizini almak için kullanabilirsiniz path/filepath.Dir.

Örnek :

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    ex, err := os.Executable()
    if err != nil {
        panic(err)
    }
    exPath := filepath.Dir(ex)
    fmt.Println(exPath)
}

ESKİ CEVAP:

Kullanabilmelisin os.Getwd

func Getwd() (pwd string, err error)

Getwd, geçerli dizine karşılık gelen köklü bir yol adı döndürür. Geçerli dizine birden çok yoldan erişilebiliyorsa (sembolik bağlantılar nedeniyle), Getwd bunlardan herhangi birini döndürebilir.

Örneğin:

package main

import (
    "fmt"
    "os"
)

func main() {
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println(pwd)
}

3
Bu, geçerli işlem çalışma dizinidir. Düğümlerde process.cwd () ile eşdeğerdir nodejs.org/api/process.html#process_process_cwd
ekanna

2
Tamam, ayrımı görüyorum. Eğer dosya (mevcut çalışma dizini yerine) ikili konum sonra runtime.Callersizin "idiomatic" en yakın olduğunu düşünüyorum
Intermernet

3
'Şubat 2017'de Çıktı' mı? Görünüşe göre zaman makinesi icat edildi ve gelecekten gelen üyelerimiz var. Gelecekteki bir sürümün güvenilir çapraz platform yöntemine sahip olacağını bilmek güzel, Bu arada şu anda mevcut çözümlere bağlı kalmalıyız.
ljgww

1
@ljgww Üzgünüm, Delorean'ımı alıp eve gideceğim :-) Cevabımı önceden güncelledim çünkü sadece yaklaşan özelliği gördüm ve cevabı daha sonra güncellemeyi unutacağımı düşündüm.
Intermernet

1
İle Düzenlendi path/filepath.Dirçünkü path.Dirsadece bir dizin ayracı olarak öne eğik çizgi (Unix tarzı) ile çalışır.
Jocelyn

63

Osext paketini kullan

ExecutableFolder()Çalışmakta olan program yürütülebilir dosyasının bulunduğu klasöre mutlak bir yol döndüren bir işlev sağlar (cron işleri için yararlıdır). Çapraz platform.

Çevrimiçi belgeler

package main

import (
    "github.com/kardianos/osext"
    "fmt"
    "log"
)

func main() {
    folderPath, err := osext.ExecutableFolder()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(folderPath)
}

13
Hem Windows hem de Linux için benim için beklenen sonuçları üreten tek cevap bu.
DannyB

3
go run main.goYerel kalkınma için kullanmak istediğinize kadar bu iyi çalışır . Her seferinde önceden bir yürütülebilir dosya oluşturmadan bunu nasıl çözeceğinizden emin değilim.
Derek Dowling

1
Üzgünüm, nasıl çalışacağını bilmiyorum go run. Bu ikili dosyalar her seferinde geçici klasöre konur.
Dobrosław Żybort

2
@DerekDowling önce bir yol go install, sonra koşmak olurdu go build -v *.go && ./main. -vDosyalar inşa ediliyor ki size söylerdim. Genel olarak, daha önce koştuğumda zamanın farklı olduğunu go runve go buildtolere edilebilir olduğunu buldum go install. go build -v {*}.go && ./main.exe
Powershell'deki

Bu geri döneceğinden $GOPATH/bin/, neden kullanmıyorsunuz $GOPATH/bin/?
fiatjaf

10
filepath.Abs("./")

Abs, yolun mutlak bir temsilini döndürür. Yol mutlak değilse, mutlak bir yola dönüştürmek için geçerli çalışma diziniyle birleştirilir.

Yorumda belirtildiği gibi, bu işlem şu anda etkin olan dizini döndürür.


8
Bu, geçerli dosyanın dizinini değil, geçerli dizini döndürür. Örneğin, yürütülebilir dosya farklı bir yoldan çağrıldıysa bu farklı olur.
Fujii

8

bu şekilde kullanırsanız:

dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
    log.Fatal(err)
}
fmt.Println(dir)

yürütülebilir dosyayı kaydedip çalıştıracağı / tmp

GeçerliWorking Directory veya 'almak için en iyi yolu düşünüyorum.' dır-dir :

import(
  "os" 
  "fmt"
  "log"
)

func main() {
  dir, err := os.Getwd()
    if err != nil {
        log.Fatal(err)
    }
  fmt.Println(dir)
}

os.Getwd () işlevi, geçerli çalışma dizini dönecektir. ve hepsi harici bir kütüphane kullanmadan: D


Bu doğru değil. Bu, işlemi yürüten kullanıcının çalışma dizinini döndürür, dosyanın dizinini döndürmez. Filepath.abs dosyasını kullanın.
PodTech.io

1
çalışan yürütülebilir dosyanın çalışma dizinini döndürür. o zaman goland gibi bir IDE kullanıyorsanız ve oluşturma seçeneklerinde çalışma dizini için bir yapılandırma yoksa / tmp'den çalışacaktır, o zaman sizin için hangi kullanım / tmp sizin için var! ?? ama os.Getwd () kullanırsanız .exe veya elf yürütülebilir dosya yolunu döndürür. not / tmp.
Bit

@Bit Böyle bir IDE'de temel hata ayıklama şablonunu kullanarak, evet bunu verin, sonra 'Yapılandırmayı Düzenle'ye basın ve' Çıktı Dizini'ni doldurun, böylece 'os.Args [0]' yolunu istediğiniz gibi
göreceksiniz

5

Kardianos tarafından osext paketi kullanıyorsanız ve Derek Dowling'in yorumladığı gibi yerel olarak test etmeniz gerekiyorsa:

Yerel geliştirme için go run main.go ile kullanmak istediğinize kadar bu iyi çalışır. Her seferinde önceden bir yürütülebilir dosya oluşturmadan bunu nasıl çözeceğinizden emin değilim.

Bunun çözümü, go run kullanmak yerine bir gorun.exe yardımcı programı yapmaktır. Gorun.exe yardımcı programı, projeyi "go build" kullanarak derleyip projenizin normal dizininde hemen çalıştırır.

Diğer derleyiciler ile bu sorunu vardı ve derleyici ile sevk edilmediğinden kendimi bu yardımcı programları yaparken buldum ... özellikle derlemek ve bağlantı ve sonra çalıştırmak (çok fazla iş) nerede C gibi araçları ile gizlidir.

Herkes benim gorun.exe (ya da elf) fikrimi seviyorsa, muhtemelen yakında github'a yükleyeceğim ..

Maalesef, bu cevap bir yorum amaçlıdır, ancak henüz yeterince büyük bir itibara sahip olmadığım için yorum yapamam.

Alternatif olarak, "go run" (zaten bu özelliğe sahip değilse), programı geçici bir dizinde (veya benzer bir şeyde) çalıştırmak için "go run -notemp" gibi bir parametreye sahip olacak şekilde değiştirilebilir. Ama kıvrımlı bir parametreden daha kısa olduğu için sadece gorun veya "gor" yazmayı tercih ederim. Gorun.exe veya gor.exe'nin, go derleyicinizle aynı dizine yüklenmesi gerekir

Ben sadece birkaç satır kod diğer derleyiciler ile yapmış gibi gorun.exe (veya gor.exe) uygulamak önemsiz olurdu ... (ünlü son kelimeler ;-)


3
Eğer "çalıştırmak go" ve yürütülebilir yerleşik hem işin onu istiyorsanız sadece kullanım _, callerFile, _, _ := runtime.Caller(0) executablePath := filepath.Dir(callerFile)yerine
Jocelyn

@Jocelyn, yorumunuz o kadar harika ki, bunu tam bir cevap haline getirmelisiniz! Bu kesinlikle benim için hile yaptı - kendi kurulumumda, çoğunlukla sözdizimi hatalarını (ve birkaç semantik olanları) yakalamak için kullandığım macOS'ta ortamın yerel bir kopyası var; sonra kodu Ubuntu Linux altında çalışan dağıtım sunucusuyla senkronize ediyorum ve elbette ortam tamamen farklı ... bu yüzden dosya yollarının şablonları, yapılandırma dosyalarını, statik olarak düzgün bir şekilde yüklemek için gerçek bir ihtiyaç var. dosyaları, vb ...
Gwyneth Llewelyn

4

os.Executable: https://tip.golang.org/pkg/os/#

filepath.EvalSymlinks: https://golang.org/pkg/path/filepath/#EvalSymlinks

Tam Demo:

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    var dirAbsPath string
    ex, err := os.Executable()
    if err == nil {
        dirAbsPath = filepath.Dir(ex)
        fmt.Println(dirAbsPath)
        return
    }

    exReal, err := filepath.EvalSymlinks(ex)
    if err != nil {
        panic(err)
    }
    dirAbsPath = filepath.Dir(exReal)
    fmt.Println(dirAbsPath)
}

4

Bazen bu yeterlidir, ilk argüman her zaman dosya yolu olur

package main

import (
    "fmt"
    "os"
)


func main() {
    fmt.Println(os.Args[0])

    // or
    dir, _ := os.Getwd()
    fmt.Println(dir)
}

0

Gustavo Niemeyer'ın cevabı harika. Ancak Windows'da, çalışma zamanı proc'u çoğunlukla başka bir dizindir, şöyle:

"C:\Users\XXX\AppData\Local\Temp"

Göreli dosya yolu kullanırsanız, örneğin "/config/api.yaml", kodunuzun bulunduğu proje yolunuzu kullanır.

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.