提问人:Alicia Wentworth 提问时间:11/6/2023 最后编辑:Alicia Wentworth 更新时间:11/6/2023 访问量:63
使用新的 io.FS 到 fs。WalkDir & 列出跨文件系统类型的文件
Using the new io.FS to fs.WalkDir & list files across filesystem types
问:
我使用的是那种新的io。FS 抽象遍历文件系统并读取与我们内部拥有的文件扩展名匹配的每个文件的前 128 个字节。
这些文件位于本地文件系统和存档文件等(ZIP 和 Tar I thunk)中。
我正在使用 fs。WalkDir,传入 fs。FS (os.DIR 和 fstest。MapFS 在我的测试中)。走路时,我返回一个“文件”数组(实际上它们是 *.pzix 和 *.pzi 文件,这是我们的专有格式)。我找不到使用 FS 接口的合适方法来获取有关我正在处理的文件的一些信息。
我想:
- 获取文件名
- 获取文件大小
- 获取 openfile 方法
我发现来自 Java/C# 的 Go 中的接口有点令人困惑。我希望对抽象进行操作,但我无法弄清楚如何获得文件本身的其他实现(例如。文件接口有 Stat() 和 read)。
我发现的最简单的事情是将路径和文件名存储在数组中,然后在我遍历数组时,确定它是否是操作系统。Dir 或 fstest。MapFS,但这似乎有悖常理:
func collectFiles(f fs.FS, root string) []string {
var files []string
fs.WalkDir(f, ".", func(p string, d fs.DirEntry, err error) error {
if !d.IsDir() { // we also check a few other things in the filename here
f = filepath.Abs(path.Join(root, p))
files = append(files, f)
}
}
return files
}
这给了我:
root = "m://" // mapfs
files = { "m://id-198271.pzi", "m://id-7125-092581.pzix"}
有没有更聪明的方法来处理抽象而不做这些事情?因为在返回数组后,我必须“打开”文件,读取前 128 个字节(签名)并对文件的其余部分进行哈希处理以确保其“有效”。
编辑:澄清一下,该方法是创建我们的主要命中文件列表,以便在另一种方法中处理。我希望将本地系统文件、zip 文件和 tar 文件传递到该方法中,以便它可以遍历存档中的文件并将它们添加到数组中。collectFiles
希望有一个 File 接口,我可以存储在数组中而不是字符串中,以便后续调用者可以在不知道底层是什么的情况下执行 f.open()。
答:
获取文件名
p
是文件系统中的名称。
获取文件大小
通过调用获取尺寸fs.Stat(f, p)
获取 openfile 方法
打开文件f.Open(p)
例:
f := os.DirFS("/etc")
fs.WalkDir(f, ".", func(p string, d fs.DirEntry, err error) error {
if !d.IsDir() {
st, _ := fs.Stat(f, p)
r, _ := f.Open(p)
defer r.Close()
// Read prefix
var buf [md5.Size]byte
n, _ := io.ReadFull(r, buf[:])
// Hash remainder
h := md5.New()
_, _ = io.Copy(h, r)
s := h.Sum(nil)
fmt.Printf("%s %d %x %x\n", p, st.Size(), buf[:n], s)
}
return nil
})
为简洁起见,该示例忽略了错误。不要在实际代码中这样做。
https://go.dev/play/p/W7He_YNSZFU
评论
type struct NameFS { name string; fsys fs.FS }
上一个:在文件链实现中绕过借用检查器
下一个:将输入重置回控制台窗口?
评论
FS
支持,这样就可以将文件,然后检查返回的文件是否实现。如果是这样,您可以读取 128 个字节,然后关闭它。根据您的描述,文件应该实现,因此您可以执行然后调用Open
f.Open
io.Reader
io.Reader
reader := file.(io.Reader)
reader.Read(...)
fs