2013-06-12 33 views
26

Tôi đang sử dụng io/ioutil để đọc một tập tin văn bản nhỏ:Làm cách nào để mở tệp bằng các đường dẫn tương đối trong Go?

fileBytes, err := ioutil.ReadFile("/absolute/path/to/file.txt") 

Và đó hoạt động tốt, nhưng điều này là không chính xác cầm tay. Trong trường hợp của tôi, các tập tin tôi muốn mở là trong GOPATH của tôi, ví dụ:

/Users/matt/Dev/go/src/github.com/mholt/mypackage/data/file.txt 

Kể từ thư mục data cưỡi quyền cùng với các mã nguồn, tôi rất muốn chỉ định đường dẫn tương đối:

data/file.txt 

Nhưng sau đó tôi nhận được lỗi này:

panic: open data/file.txt: no such file or directory

Làm thế nào tôi có thể mở các file sử dụng đường dẫn tương đối của họ, đặc biệt là nếu họ sống bên cạnh đang Go của tôi?

+5

Các GOPATH có không phải là một ý nghĩa lớn khi chương trình của bạn được biên dịch, và thậm chí ít hơn khi bạn phân phối nó. –

+0

Những gì bạn có vẻ muốn trông giống như một số nhúng của các tập tin trong chương trình biên dịch của bạn. –

+2

Loại ... ngoại trừ tôi muốn các tệp dữ liệu tách biệt với nguồn. Các tệp dữ liệu quan trọng đối với chức năng của chương trình. Vì vậy, khi ai đó kéo xuống mã nguồn của tôi (với các tệp dữ liệu bên cạnh nó) và biên dịch và chạy nó, các tệp dữ liệu được tải bằng cách sử dụng đường dẫn tương đối vì chúng tồn tại gần mã nguồn hoặc gần nơi chương trình đang thực thi. – Matt

Trả lời

40

Hmm ... gói path/filepathAbs() mà làm những gì tôi cần (cho đến nay) mặc dù đó là một chút bất tiện:

absPath, _ := filepath.Abs("../mypackage/data/file.txt") 

Sau đó, tôi sử dụng absPath để tải các tập tin và nó hoạt động tốt.

Lưu ý rằng, trong trường hợp của tôi, các tệp dữ liệu nằm trong gói riêng biệt với gói main mà từ đó tôi đang chạy chương trình. Nếu tất cả nằm trong cùng một gói, tôi sẽ xóa ../mypackage/ hàng đầu. Vì đường dẫn này rõ ràng là tương đối, các chương trình khác nhau sẽ có cấu trúc khác nhau và cần điều chỉnh này cho phù hợp.

Nếu có cách nào tốt hơn để sử dụng tài nguyên bên ngoài bằng chương trình Go và giữ cho nó di động, vui lòng đóng góp một câu trả lời khác.

+0

Ha, gần một năm sau đó vào Go, và tôi chưa bao giờ gặp vấn đề khi mở tập tin bằng đường dẫn tương đối kể từ đó, tôi cũng không phải sử dụng mẹo nhỏ này. Tôi đoán điều đó có nghĩa là tôi đã học được điều gì đó. – Matt

+8

Bạn đã học được gì? :) Chúng ta có nên chia sẻ các tệp như thế này trên các gói không? – srt32

+3

@Matt, chia sẻ tình yêu. Không muốn sử dụng "mẹo nhỏ" này nếu bạn có thứ gì đó tốt hơn cho chúng tôi. Bạn là kết quả hàng đầu trên google. – OGHaza

6

Tôi đã viết gobundle để giải quyết chính xác vấn đề này. Nó tạo mã nguồn Go từ các tệp dữ liệu, sau đó bạn biên dịch thành mã nhị phân của mình. Sau đó, bạn có thể truy cập dữ liệu tệp qua lớp giống như VFS. Nó hoàn toàn di động, hỗ trợ thêm toàn bộ cây tập tin, nén, vv

Nhược điểm là bạn cần một bước trung gian để xây dựng các tập tin Go từ dữ liệu nguồn. Tôi thường sử dụng làm cho việc này.

Đây là cách bạn muốn lặp qua tất cả các tập tin trong một bó, đọc các byte:

for _, name := range bundle.Files() { 
    r, _ := bundle.Open(name) 
    b, _ := ioutil.ReadAll(r) 
    fmt.Printf("file %s has length %d\n", name, len(b)) 
} 

Bạn có thể thấy một ví dụ thực tế của việc sử dụng nó trong gói GeoIP tôi. Makefile tạo mã và geoip.go sử dụng VFS.

+0

@ BurntSushi5 có điểm tốt; các tệp dữ liệu của tôi có kích thước hàng trăm MB. Điều này thật tuyệt, nhưng tôi không nghĩ rằng việc biên dịch các tệp văn bản thuần túy thành nhị phân là một lựa chọn khả thi. – Matt

1

Tôi nghĩ rằng Alec Thomas đã cung cấp Câu trả lời, nhưng theo kinh nghiệm của tôi, điều đó không phải là không dễ dàng. Một vấn đề tôi gặp phải khi biên dịch tài nguyên thành nhị phân là việc biên dịch có thể đòi hỏi nhiều bộ nhớ tùy thuộc vào kích thước tài sản của bạn. Nếu chúng nhỏ, thì có lẽ không có gì phải lo lắng. Trong kịch bản cụ thể của tôi, một tập tin phông chữ 1MB đã gây ra biên dịch để yêu cầu một nơi nào đó khoảng 1GB bộ nhớ để biên dịch. Đó là một vấn đề bởi vì tôi muốn nó được đi trên một Raspberry Pi. Điều này là với Go 1.0; mọi thứ có thể đã được cải thiện trong Go 1.1.

Vì vậy, trong trường hợp cụ thể đó, tôi chọn chỉ sử dụng gói go/build để tìm số source directory của chương trình dựa trên đường dẫn nhập.Tất nhiên, điều này đòi hỏi rằng các mục tiêu của bạn có một thiết lập GOPATH và nguồn đó có sẵn. Vì vậy, nó không phải là một giải pháp lý tưởng trong mọi trường hợp.

12

này dường như làm việc khá tốt:

import "os" 
import "io/ioutil" 

pwd, _ := os.Getwd() 
txt, _ := ioutil.ReadFile(pwd+"/path/to/file.txt") 
Các vấn đề liên quan