package local import ( "io" "os" "path/filepath" clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types" ) type DirReader struct { // 完整的根路径(包括ReadDir的path参数),比如包括了盘符 absRootPath string // ReadDir函数传递进来的path参数 rootJPath clitypes.JPath init bool curEntries []dirEntry } func (r *DirReader) Next() (types.DirEntry, error) { if !r.init { info, err := os.Stat(r.absRootPath) if err != nil { return types.DirEntry{}, err } if !info.IsDir() { r.init = true return types.DirEntry{ Path: r.rootJPath, Size: info.Size(), ModTime: info.ModTime(), IsDir: false, }, nil } es, err := os.ReadDir(r.absRootPath) if err != nil { return types.DirEntry{}, err } for _, e := range es { r.curEntries = append(r.curEntries, dirEntry{ dir: clitypes.JPath{}, entry: e, }) } r.init = true } if len(r.curEntries) == 0 { return types.DirEntry{}, io.EOF } entry := r.curEntries[0] r.curEntries = r.curEntries[1:] if entry.entry.IsDir() { es, err := os.ReadDir(filepath.Join(r.absRootPath, entry.dir.JoinOSPath(), entry.entry.Name())) if err != nil { return types.DirEntry{}, nil } // 多个entry对象共享同一个JPath对象,但因为不会修改JPath,所以没问题 dir := entry.dir.Clone() dir.Push(entry.entry.Name()) for _, e := range es { r.curEntries = append(r.curEntries, dirEntry{ dir: dir, entry: e, }) } } info, err := entry.entry.Info() if err != nil { return types.DirEntry{}, err } p := r.rootJPath.ConcatNew(entry.dir) p.Push(entry.entry.Name()) if entry.entry.IsDir() { return types.DirEntry{ Path: p, Size: 0, ModTime: info.ModTime(), IsDir: true, }, nil } return types.DirEntry{ Path: p, Size: info.Size(), ModTime: info.ModTime(), IsDir: false, }, nil } func (r *DirReader) Close() { } type dirEntry struct { dir clitypes.JPath entry os.DirEntry } type fileInfoDirEntry struct { info os.FileInfo } func (d fileInfoDirEntry) Name() string { return d.info.Name() } func (d fileInfoDirEntry) IsDir() bool { return d.info.IsDir() } func (d fileInfoDirEntry) Type() os.FileMode { return d.info.Mode().Type() } func (d fileInfoDirEntry) Info() (os.FileInfo, error) { return d.info, nil }