Làm thế nào để có được thư mục của tập tin hiện đang chạy?


239

Trong nodejs tôi sử dụng __dirname . Tương đương với điều này ở Golang là gì?

Tôi đã googled và tìm ra bài viết này http://andrewbrookins.com/tech/golang-get-directory-of-the-civerse-file/ . Nơi anh ta sử dụng mã dưới đây

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

Nhưng đó có phải là cách đúng đắn hay thành ngữ để làm ở Golang?


đây không phải là câu trả lời cho câu hỏi của bạn nhưng bạn có thể lưu đường dẫn đến var toàn cầu (vị trí tệp của bạn không thể thay đổi trong khi chạy :)) không chạy os.open nhiều lần mỗi khi mã của bạn chạy
oguzalb

Bạn nên vượt qua 0, không 1, để runtime.Caller().
fiatjaf

4
runtime.Caller(0)sẽ cung cấp cho bạn đường dẫn của tệp nguồn, như thế nào $GOPATH/src/packagename/main.go. Các câu trả lời khác trong chuỗi này đang cố gắng trả về đường dẫn của tệp thực thi (như $GOPATH/bin/packagename).
fiatjaf

Bạn đang giả sử chương trình đang chạy từ một tệp ...
Flimzy

Câu trả lời:


221

Điều này nên làm điều đó:

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
Có thể có một lỗi ở đây? Nếu vậy, lỗi sẽ là gì, chỉ vì tò mò?
Jeff Escalante

4
Không hoạt động đối với tôi play.golang.org/p/c8fe-Zm_bH - os.Arss [0] không nhất thiết phải chứa đường dẫn abs.
zupa

5
Nó thực sự hoạt động ngay cả khi os.Arss [0] không chứa đường dẫn abs. Lý do kết quả sân chơi không như bạn mong đợi là vì nó nằm trong hộp cát.
Gustavo Niemeyer

37
Đây không phải là một cách đáng tin cậy , hãy xem câu trả lời về việc sử dụng osext vì đây là cách triển khai có hiệu quả với tất cả các khách hàng của chúng tôi trên các HĐH khác nhau. Tôi đã triển khai mã bằng phương pháp này nhưng có vẻ không đáng tin cậy lắm và nhiều người dùng phàn nàn về các lỗi gây ra bởi phương pháp này đã chọn sai đường dẫn cho tệp thực thi.
JD D

5
Có kết quả tương tự như emrah khi sử dụng Go 1.6 trên Windows (có đường dẫn của thư mục temp thay vì thư mục tệp nguồn). Để có được đường dẫn của thư mục tệp nguồn của bạn mà không sử dụng bất kỳ phụ thuộc bên ngoài nào, hãy sử dụng phiên bản sửa đổi của mã OP: _, currentFilePath, _, _ := runtime.Caller(0) dirpath := path.Dir(currentFilePath)(lưu ý runtime.Caller(0)thay vì runtime.Caller(1))
TanguyP 13/03/2016

295

EDIT: Kể từ Go 1.8 (Phát hành tháng 2 năm 2017), cách thức được đề xuất là os.Executable:

func Executable() (string, error)

Thực thi trả về tên đường dẫn cho thực thi đã bắt đầu quá trình hiện tại. Không có gì đảm bảo rằng đường dẫn vẫn đang trỏ đến tệp thực thi chính xác. Nếu một liên kết tượng trưng được sử dụng để bắt đầu quá trình, tùy thuộc vào hệ điều hành, kết quả có thể là liên kết tượng trưng hoặc đường dẫn mà nó trỏ đến. Nếu cần một kết quả ổn định, đường dẫn / filepath.EvalSymlinks có thể giúp ích.

Để có được chỉ mục của thư mục thực thi, bạn có thể sử dụng path/filepath.Dir.

Ví dụ :

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

TRẢ LỜI:

Bạn sẽ có thể sử dụng os.Getwd

func Getwd() (pwd string, err error)

Getwd trả về một tên đường dẫn gốc tương ứng với thư mục hiện tại. Nếu thư mục hiện tại có thể được truy cập thông qua nhiều đường dẫn (do các liên kết tượng trưng), Getwd có thể trả về bất kỳ một trong số chúng.

Ví dụ:

package main

import (
    "fmt"
    "os"
)

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

3
Đây là quá trình làm việc thư mục hiện tại. Trong nodejs, nó tương đương với process.cwd () nodejs.org/api/ process.html # process_ process_cwd
ekanna

2
Ok, tôi thấy sự khác biệt. Của bạn sau vị trí của nhị phân trong các tập tin (chứ không phải là thư mục làm việc hiện tại) Tôi nghĩ đó runtime.Callerlà lần gần nhất bạn sẽ nhận được "thành ngữ"
Intermernet

3
'Phát hành tháng 2 năm 2017'? Có vẻ như cỗ máy thời gian đã được phát minh và chúng tôi có các thành viên đăng bài từ tương lai. Thật tuyệt khi biết một phiên bản trong tương lai sẽ có phương pháp đa nền tảng đáng tin cậy, trong khi đó, chúng tôi phải bám sát các giải pháp hiện có.
ljgww

1
@ljgww Xin lỗi, tôi sẽ đưa Delorean của mình và về nhà :-) Tôi đã cập nhật câu trả lời của mình trước vì tôi chỉ thấy tính năng sắp tới đó và hình dung tôi sẽ quên cập nhật câu trả lời sau.
Intermernet

1
Được chỉnh sửa path/filepath.Dirpath.Dirchỉ hoạt động với dấu gạch chéo (kiểu Unix) làm dấu tách thư mục.
Jocelyn

63

Sử dụng gói osext

Đó là chức năng cung cấp ExecutableFolder()trả về một đường dẫn tuyệt đối đến thư mục chứa chương trình thực thi chương trình đang chạy (hữu ích cho các công việc định kỳ). Đó là nền tảng chéo.

Tài liệu trực tuyến

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
Đây là câu trả lời duy nhất tạo ra kết quả mong đợi cho tôi cả trên Windows và Linux.
DannyB

3
Điều này hoạt động tốt cho đến khi bạn muốn sử dụng nó go run main.gocho phát triển địa phương. Không chắc chắn làm thế nào tốt nhất để có được xung quanh đó mà không xây dựng một thực thi trước mỗi lần.
Derek Dowling

1
Xin lỗi tôi không biết làm thế nào để làm cho nó hoạt động go run. Các tệp nhị phân này được đặt trong thư mục tạm thời mỗi lần.
Dobrosław ybort

2
@DerekDowling một cách đầu tiên sẽ làm một go install, sau đó chạy go build -v *.go && ./main. Điều -vnày sẽ cho bạn biết những tập tin đang được xây dựng. Nói chung, tôi thấy rằng thời gian khác nhau giữa go rungo buildcó thể chấp nhận được nếu tôi đã chạy go install. Đối với người dùng windows trên powershell, lệnh sẽ làgo build -v {*}.go && ./main.exe
kumarharsh

Vì điều này sẽ trở lại $GOPATH/bin/, tại sao không sử dụng $GOPATH/bin/?
fiatjaf

10
filepath.Abs("./")

Abs trả về một đại diện tuyệt đối của đường dẫn Nếu đường dẫn không tuyệt đối, nó sẽ được nối với thư mục làm việc hiện tại để biến nó thành một đường dẫn tuyệt đối.

Như đã nêu trong bình luận, điều này trả về thư mục hiện đang hoạt động.


8
Điều này trả về thư mục hiện tại, không phải thư mục của tập tin hiện tại. Ví dụ, điều này sẽ khác nếu tệp thực thi được gọi từ một đường dẫn khác.
Fujii

8

nếu bạn sử dụng theo cách này:

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

bạn sẽ nhận được đường dẫn / tmp khi bạn đang chạy chương trình bằng một số IDE như GoLang vì tệp thực thi sẽ lưu và chạy từ / tmp

tôi nghĩ rằng cách tốt nhất để có được Thư mục làm việc hiện tại hoặc '.' Là :

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

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

các os.Getwd () chức năng sẽ trở lại thư mục làm việc hiện hành. và tất cả mà không sử dụng bất kỳ thư viện bên ngoài: D


Điều này LAF không đúng. Điều này trả về thư mục làm việc của người dùng thực thi quy trình chứ không phải thư mục của tệp. Sử dụng filepath.abs.
PodTech.io

1
nó trả về thư mục làm việc của tập tin thực thi đang chạy. sau đó nếu bạn đang sử dụng một IDE như goland và không có cấu hình cho thư mục làm việc trong các tùy chọn xây dựng thì nó sẽ chạy từ / tmp, vậy thì cách sử dụng / tmp có cho bạn! ?? nhưng nếu bạn sử dụng os.Getwd () thì nó trả về đường dẫn tệp thực thi .exe hoặc elf. không / tmp.
Bit

@Bit Sử dụng mẫu cơ sở để gỡ lỗi trong một IDE như vậy, có cung cấp cho bạn điều đó, sau đó chỉ cần nhấn 'Chỉnh sửa cấu hình' và điền vào 'Thư mục đầu ra', vì vậy bạn sẽ thấy đường dẫn 'os.Arss [0]' là những gì bạn muốn
ϻαϻɾΣɀ602 -MaMrEzO

5

Nếu bạn sử dụng gói osext của kardianos và bạn cần kiểm tra cục bộ, như Derek Dowling đã nhận xét:

Điều này hoạt động tốt cho đến khi bạn muốn sử dụng nó với chạy main.go để phát triển cục bộ. Không chắc chắn làm thế nào tốt nhất để có được xung quanh đó mà không xây dựng một thực thi trước mỗi lần.

Giải pháp cho vấn đề này là tạo một tiện ích gorun.exe thay vì sử dụng go run. Tiện ích gorun.exe sẽ biên dịch dự án bằng cách sử dụng "go build", sau đó chạy nó ngay sau đó, trong thư mục bình thường của dự án của bạn.

Tôi gặp vấn đề này với các trình biên dịch khác và thấy mình tạo ra các tiện ích này vì chúng không được cung cấp cùng với trình biên dịch ... nó đặc biệt phức tạp với các công cụ như C nơi bạn phải biên dịch và liên kết và sau đó chạy nó (quá nhiều công việc).

Nếu bất cứ ai thích ý tưởng của tôi về gorun.exe (hoặc elf), tôi có thể sẽ sớm tải nó lên github ..

Xin lỗi, câu trả lời này có ý nghĩa như một bình luận, nhưng tôi không thể bình luận do tôi chưa có một danh tiếng đủ lớn.

Ngoài ra, "go run" có thể được sửa đổi (nếu nó chưa có tính năng này) để có một tham số như "go run -notemp" để không chạy chương trình trong một thư mục tạm thời (hoặc một cái gì đó tương tự). Nhưng tôi thích chỉ cần gõ gorun hoặc "gor" vì nó ngắn hơn một tham số phức tạp. Gorun.exe hoặc gor.exe sẽ cần phải được cài đặt trong cùng thư mục với trình biên dịch đi của bạn

Việc triển khai gorun.exe (hoặc gor.exe) sẽ không quan trọng, vì tôi đã thực hiện nó với các trình biên dịch khác chỉ trong một vài dòng mã ... (những từ cuối nổi tiếng ;-)


3
Nếu bạn muốn nó hoạt động với cả "go run" và được xây dựng có thể thực thi được thì chỉ cần sử dụng _, callerFile, _, _ := runtime.Caller(0) executablePath := filepath.Dir(callerFile)thay vào đó
Jocelyn

@Jocelyn, bình luận của bạn tuyệt vời đến mức bạn nên biến nó thành một câu trả lời đầy đủ! Điều này chắc chắn đã tạo ra mánh khóe cho tôi - trên thiết lập của riêng tôi, tôi có một bản sao cục bộ của môi trường trong macOS, mà tôi chủ yếu sử dụng để bắt lỗi cú pháp (và một vài ngữ nghĩa); sau đó tôi đồng bộ mã với máy chủ triển khai chạy trên Ubuntu Linux và tất nhiên môi trường hoàn toàn khác ... vì vậy cần phải tìm ra đường dẫn tệp ở đâu để tải đúng mẫu, tệp cấu hình, tĩnh các tập tin, v.v ...
Gwyneth Llewelyn


4

Đôi khi điều này là đủ, đối số đầu tiên sẽ luôn là đường dẫn tệp

package main

import (
    "fmt"
    "os"
)


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

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

0

Câu trả lời của Gustavo Niemeyer là tuyệt vời. Nhưng trong Windows, thời gian chạy phần lớn là trong một thư mục khác, như thế này:

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

Nếu bạn sử dụng đường dẫn tệp tương đối, như "/config/api.yaml", điều này sẽ sử dụng đường dẫn dự án của bạn nơi mã của bạn tồn tại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.