Lấy thư mục chính của người dùng


93

Cách sau đây có phải là cách tốt nhất để lấy được thư mục chính của người dùng đang chạy không? Hoặc có một chức năng cụ thể nào mà tôi đã xem qua?

os.Getenv("HOME")

Nếu điều trên là chính xác, có ai biết liệu cách tiếp cận này có được đảm bảo hoạt động trên các nền tảng không phải Linux hay không, chẳng hạn như Windows?


2
$HOMEkhông nhất thiết phải là thư mục chính của người dùng. Ví dụ, tôi có thể viết export HOME=/something/elsetrước khi khởi chạy chương trình của bạn. Thông thường, điều đó có nghĩa là tôi muốn chương trình coi /something/elsenhư thư mục chính của mình vì lý do nào đó và thường thì chương trình sẽ chấp nhận điều đó. Nhưng nếu bạn thực sự cần của người dùng thực tế thư mục home, một biến môi trường sẽ không nhất thiết phải đưa nó cho bạn.
Keith Thompson

1
@KeithThompson Cảm ơn nhưng đối với mục đích của tôi, nó đủ tốt.
Paul Ruane

Câu trả lời:


175

Trong phiên bản 1.0.3 (có thể trước đó cũng vậy), các hoạt động sau:

package main
import (
    "os/user"
    "fmt"
    "log"
)
func main() {
    usr, err := user.Current()
    if err != nil {
        log.Fatal( err )
    }
    fmt.Println( usr.HomeDir )
}

Nếu điều quan trọng để cross-compile là, xem xét các homedirthư viện


1
Tuyệt vời, cảm ơn nhiều. Không biết về sự thay đổi này. Điều này thật đúng với gì mà tôi đã tìm kiếm.
Paul Ruane 22/10/12

Có phải chỉ tôi hay tôi là người duy nhất thực hiện việc này trên Windows mất vài giây?
Htbaa

Nó chắc chắn có vẻ ngay lập tức trên máy ảo Windows 7 64bit của tôi.
Vlad Didenko

4
Lưu ý rằng kể từ ngày 1.1, "usr, err: = user.Current ()" sẽ tạo ra lỗi "user: current not implement on darwin / amd64" trên osx.
Oleiade,

11
không hoạt động khi mã được biên dịch chéo code.google.com/p/go/issues/detail?id=6376
Vishnu

59

os.UserHomeDir ()

Trong go1.12 +, bạn có thể sử dụng os.UserHomeDir ()

home, err := os.UserHomeDir()

Xem https://golang.org/pkg/os/#UserHomeDir

Điều đó sẽ hoạt động ngay cả khi không bật CGO (tức là FROM scratch) và không cần phải phân tích cú pháp /etc/passwdhoặc những thứ vô nghĩa khác.


23

Ví dụ,

package main

import (
    "fmt"
    "os"
    "runtime"
)

func UserHomeDir() string {
    if runtime.GOOS == "windows" {
        home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
        if home == "" {
            home = os.Getenv("USERPROFILE")
        }
        return home
    }
    return os.Getenv("HOME")
}

func main() {
    dir := UserHomeDir()
    fmt.Println(dir)
}

1
Đây là cách tiếp cận tương tự như Jeremy W Sherman, dường như là cách duy nhất hiện nay. Cảm ơn nhiều.
Paul Ruane

2
Đây là cách tiếp cận được theo sau trong viper use.go userHomeDir ()
RubenLaguna

Trong hầu hết các trường hợp tôi thấy điều này được sử dụng, đây KHÔNG phải là điều đúng đắn để làm. USERPROFILElà gốc của không gian lưu trữ của Người dùng trên hệ thống, nhưng KHÔNG phải là nơi mà các ứng dụng sẽ được ghi vào bên ngoài lời nhắc hộp thoại lưu. Nếu bạn có cấu hình ứng dụng, nó sẽ được ghi vào APPDATAvà nếu bạn có bộ đệm ứng dụng (hoặc các tệp lớn không được đồng bộ hóa qua mạng) thì nó sẽ được ghi LOCALAPPDATAvào Windows.
Micah Zoltu

4

Đây là một cách hay và ngắn gọn để làm điều đó (nếu bạn chỉ chạy trên hệ thống dựa trên UNIX):

import (
  "os"
)

var home string = os.Getenv("HOME")

Điều đó chỉ truy vấn biến môi trường $ HOME.

--- Biên tập ---

Bây giờ tôi thấy rằng phương pháp tương tự đã được đề xuất ở trên. Tôi sẽ để ví dụ này ở đây như một giải pháp chắt lọc.


2
1. nó đã được đề xuất trước đây, 2. nó không đa nền tảng, 3. câu trả lời được chấp nhận đã giải quyết vấn đề này theo cách tốt hơn.
Paul Ruane

3

Câu trả lời tương tự cho @peterSO nhưng tôn trọng XDG_CONFIG_HOMEđường dẫn cho linux.

package main

import (
    "fmt"
    "os"
    "runtime"
)

func userHomeDir() string {
    if runtime.GOOS == "windows" {
        home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
        if home == "" {
            home = os.Getenv("USERPROFILE")
        }
        return home
    } else if runtime.GOOS == "linux" {
        home := os.Getenv("XDG_CONFIG_HOME")
        if home != "" {
            return home
        }
    }
    return os.Getenv("HOME")
}

func main() {
    fmt.Println(userHomeDir())
}

Rất thích xem câu trả lời này được cập nhật để tôn trọng Windows quá! APPDATAđể cấu hình và LOCALAPPDATAcho các tệp lớn. Đối với mục đích chung là "nhà", tôi khuyên LOCALAPPDATAcác nhà phát triển ứng dụng mặc định không phá hủy mạng công ty. 😊
Micah Zoltu

2

Bạn nên sử dụng biến môi trường USERPROFILEhoặc HOMEPATHtrong Windows. Xem Các biến môi trường được công nhận (một liên kết tài liệu apropos khác sẽ được hoan nghênh).


Cảm ơn. Có phải bạn đang nói rằng HOME không được Go phổ biến cho mỗi nền tảng (mà nó ủy quyền trực tiếp vào O / S env vars) và tôi phải kiểm tra biến tương ứng của từng nền tảng để xác định thư mục chính?
Paul Ruane

Tôi đã xem qua nguồn và có vẻ như HOME không được điền tự động. Có vẻ như (hiện tại) không có cơ sở bất khả tri nền tảng nào để lấy được thư mục chính.
Paul Ruane

@PaulRuane Vì các nền tảng sử dụng các biến khác nhau nên chỉ cần bỏ qua Hệ điều hành, kiểm tra cả hai biến và đi với bất kỳ biến nào được điền. Nếu cả hai đều được xác định, tôi sẽ sử dụng HOME, vì điều đó có thể có nghĩa là bạn đang chạy dưới cygwin.
Jeremy W. Sherman,

Bạn KHÔNG nên sử dụng USERPROFILEhoặc HOMEPATHtrên Windows trong phần lớn các trường hợp. Trong hầu hết các trường hợp các nhà phát triển sử dụng chúng, những gì họ nên sử dụng là APPDATAhoặc LOCALAPPDATA(tùy thuộc vào việc nội dung đồng bộ hóa qua mạng khi đăng nhập / đăng xuất có hợp lý hay không).
Micah Zoltu

2

go1.8rc2 có hàm go / build / defaultGOPATH lấy thư mục chính. https://github.com/golang/go/blob/go1.8rc2/src/go/build/build.go#L260-L277

Đoạn mã sau được trích xuất từ ​​hàm defaultGOPATH.

package main

import (
    "fmt"
    "os"
    "runtime"
)

func UserHomeDir() string {
    env := "HOME"
    if runtime.GOOS == "windows" {
        env = "USERPROFILE"
    } else if runtime.GOOS == "plan9" {
        env = "home"
    }
    return os.Getenv(env)
}

func main() {
    dir := UserHomeDir()
    fmt.Println(dir)
}

Mặc dù việc triển khai hàm Go này rất thú vị, nhưng đây là một giải pháp tồi tệ hơn là sử dụng hàm thư viện chuẩn được mô tả trong câu trả lời được chấp nhận. (Và là cách tiếp cận tương tự như câu trả lời peterSO từ sáu năm trước.)
Paul Ruane

Đây không phải là giải pháp đúng trong hầu hết các trường hợp . Xem ý kiến về câu trả lời khác, nhưng TL; DR là APPDATAhoặc LOCALAPPDATAlà gần như lúc nào cũng là lựa chọn đúng đắn, không USERPROFILE, trên Windows.
Micah Zoltu
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.