-
Notifications
You must be signed in to change notification settings - Fork 18k
proposal: embed: read file contents directly from FS during fs.WalkDir #45815
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
FWIW, here's a runnable version of your code: https://play.golang.org/p/XkgAqsOBcJa You can use fs.ReadFile whether an fs provides ReadFile or not and it will fallback to io.ReadAll, so I'm not sure why you'd need WalkRead. The error passed into the WalkDirFunc is from errors trying to open a directory. For an embed.FS, you can just ignore it, or panic if you want, since they can't happen. Here is a simplified version of your code: err := fs.WalkDir(static, ".", func(path string, d fs.DirEntry, err error) error {
// cannot happen
if err != nil {
panic(err)
}
if d.IsDir() {
return nil
}
b, err := fs.ReadFile(static, path)
if err != nil {
return err // or panic or ignore
}
log.Printf("%q", b)
return nil
}) Playing with this code does make me aware that there's no way inside of a WalkDirFunc to see the fs that's being walked, which is a little unfortunate. It means the WalkDirFunc needs to be a closure over fsys. But in practice, I don't think many people are writing reusable WalkDirFuncs anyway, so I don't think it's a real limitation. FWIW, in my experience, it's usually reads best to have the WalkDirFunc just collect valid path names in a slice and then do the processing after the walking is over. That also makes it easier to fan out goroutines if that's needed for performance. If you're doing it that way, the WalkDirFunc is usually pretty short and mostly just comparing file names to some pattern or another. |
It does seem like in the case where the Open+Read+Close are guaranteed to succeed, it suffices to write
That's just one line. It doesn't seem worth adding new API to avoid writing one line. |
This proposal has been added to the active column of the proposals project |
Based on the discussion above, this proposal seems like a likely decline. |
this seems like a really sharp edge. much like #45961 I am certian you or I could convince ourselves of if an |
func EmbedFSOnlyWalkDir(fsys embed.FS, path string, f fs.WalkDirFunc) error {
return fs.WalkDir(fsys, path, f)
} |
No change in consensus, so declined. |
so, just to confirm there is not any solution for performance concerns and the suggested alternative is to simply ignore errors? |
The suggestion is to use |
background
Currently there is no ergonomic way to walk an
embed.FS
and interact with file contents without handling a number of errors that are guaranteed to benil
.Each
fs.DirEntry
, when using anembed.FS
, is actually anembed.file
that contains all the data that I want to use inio.Copy
, however it is gated behind thedata.Open
call.I understand that for a general file system this type of feature may be dangerous or unnecessary, as sometimes things change between stat and open, however for
embed.FS
these are invariants.proposal
I can envision a new interface that gives direct access to the raw data:
I am not sold on this exact syntax, and it would need to document that it is just for ripping through file data, but think that there exists something for this problem space.
alternatives
With sufficient testing, this could be implemented in an extended standard library as syntax sugar, but the amount of errors that would be ignored (or panicked) and data buffering scares me:
Since there likely exist other cases that would benefit from this (immutable, in memory, or loops where you intend to read every file), it may be useful to create a more generic interface in the
io/fs
package instead ofembed
. This will require more exported symbols and may not be worth the hassle.Currently, the
embed.file.Sys
method always returnsnil
, it may be considered a breaking change to start providing a value, but if that could be something useful likeembed.openFile
/embed.openDir
, you could abuse it like so:Using the existing interface, I could just
panic
, but this feels like bad form, and my goal is to simplify the interface:The text was updated successfully, but these errors were encountered: