Closed twpayne closed 3 years ago
I'd even go as far as to add a MustOpen
and MustReadFile
function - it would make it so much easier to work with pkger...
Here's an example, to give a bit of context regarding this issue:
f, err := pkger.Open("/example.txt") // can't use a wrapper function or pkger doesn't pack it!
if err != nil {
panic(err) // we know that this file exists, so this is just to be sure and to get error messages that make sense
}
b, err := ioutil.ReadAll(f)
if err != nil {
panic(err) // this will hopefully only possibly panic during development as the file is already in memory otherwise
}
s := string(b)
Let's say I have to load 3 files at once, that gets really complex, and it's a very common pattern. The shortest way I could think of would be to create a wrapper function like this:
func MustReadAll(f io.Reader, err error) []byte {
if err != nil {
panic(err)
}
b, err := ioutil.ReadAll(f)
if err != nil {
panic(err)
}
return b
}
//...
f, err := pkger.Open("/example.txt")
s1 := string(MustReadAll(f, err))
f, err = pkger.Open("/example2.txt")
s2 := string(MustReadAll(f, err))
f, err = pkger.Open("/example3.txt")
s3 := string(MustReadAll(f, err))
That's a lot of boilerplate code for a very simple example - as we're not using the filesystem in a production build, panicking seems like a fine way to handle errors in pkger to me (at least if it's obvious thanks to the Must
prefix).
A way simpler approach would be this one:
s1 := string(pkger.MustReadFile("/example.txt"))
s2 := string(pkger.MustReadFile("/example2.txt"))
s3 := string(pkger.MustReadFile("/example3.txt"))
Or, if I want to catch the errors:
b1, err1 := pkger.ReadFile("/example.txt")
b2, err2 := pkger.ReadFile("/example2.txt")
b3, err3 := pkger.ReadFile("/example3.txt")
if err1 != nil || err2 != nil || err3 != nil {
log.Fatalf("Couldn't load at least one of the example files: %v; %v; %v\n", err1, err2, err3)
}
s1 := string(b1)
s2 := string(b2)
s3 := string(b3)
@twpayne PRs are welcome. There was one once, however, to make it useful it needs to be added to all of the implementations, and be a required part of the Pkger interface. The alternatives are you have to pass the Pkger implementation into the function to read the file, which is also cumbersome amd cumbersome.
@moqmar I’m sorry, but there won’t be any Must functions or panicking in this application.
It must be remembered that Pkger mimics the std library and Go doesn’t have those functions for working with files.
Remember, you can use pkger.Include
in init() of your package to pre-include all the needed files, then you can make a helper function that uses pkger.Open()
with variables and it will work fine.
func load(filename string) (string, error) {
f, err := pkger.Open(filename)
if err != nil {
return "", err
}
b, err := ioutil.ReadAll(f)
if err != nil {
return "", err
}
return string(b), nil
}
@markbates you should probably mention this trick in the README
Thanks for the tip @Xeoncross! It proved useful to me!
I assume that this package is now superseded by Go's embed
, so closing this.
Go has a very useful
ioutil.ReadFile
function which slurps an entire file into memory.It would be very helpful to have an equivalent both at the top level and as part of the
Pkger
interface.