package file import ( "errors" "fmt" "os" "path" "path/filepath" "strings" "be.ems/lib/file" "github.com/spf13/afero" ) // 获取文件列表 func GetFileList(op FileOption) (FileInfo, error) { var fileInfo FileInfo if _, err := os.Stat(op.Path); err != nil && os.IsNotExist(err) { return fileInfo, nil } info, err := NewFileInfo(op) if err != nil { return fileInfo, err } fileInfo = *info return fileInfo, nil } func NewFileInfo(op FileOption) (*FileInfo, error) { var appFs = afero.NewOsFs() info, err := appFs.Stat(op.Path) if err != nil { return nil, err } fileInfo := &FileInfo{ Fs: appFs, Path: op.Path, Name: info.Name(), IsDir: info.IsDir(), FileMode: info.Mode(), ModTime: info.ModTime(), Size: info.Size(), IsSymlink: file.IsSymlink(info.Mode()), Extension: filepath.Ext(info.Name()), IsHidden: file.IsHidden(op.Path), Mode: fmt.Sprintf("%04o", info.Mode().Perm()), MimeType: file.GetMimeType(op.Path), } if fileInfo.IsSymlink { fileInfo.LinkPath = file.GetSymlink(op.Path) } if op.Expand { if fileInfo.IsDir { if err := listChildren(fileInfo, op.Dir, op.ShowHidden, op.ContainSub, op.Search, op.Page, op.PageSize); err != nil { return nil, err } return fileInfo, nil } else { if err := getContent(fileInfo); err != nil { return nil, err } } } return fileInfo, nil } func listChildren(f *FileInfo, dir, showHidden, containSub bool, search string, page, pageSize int) error { afs := &afero.Afero{Fs: f.Fs} var ( files []FileSearchInfo err error total int ) if search != "" && containSub { files, total, err = f.search(search, page*pageSize) if err != nil { return err } } else { dirFiles, err := afs.ReadDir(f.Path) if err != nil { return err } for _, file := range dirFiles { files = append(files, FileSearchInfo{ Path: f.Path, FileInfo: file, }) } } var items []*FileInfo for _, df := range files { if dir && !df.IsDir() { continue } name := df.Name() fPath := path.Join(df.Path, df.Name()) if search != "" { if containSub { fPath = df.Path name = strings.TrimPrefix(strings.TrimPrefix(fPath, f.Path), "/") } else { lowerName := strings.ToLower(name) lowerSearch := strings.ToLower(search) if !strings.Contains(lowerName, lowerSearch) { continue } } } if !showHidden && file.IsHidden(name) { continue } f.ItemTotal++ isSymlink, isInvalidLink := false, false if file.IsSymlink(df.Mode()) { isSymlink = true info, err := f.Fs.Stat(fPath) if err == nil { df.FileInfo = info } else { isInvalidLink = true } } fileInfo := &FileInfo{ Fs: f.Fs, Name: name, Size: df.Size(), ModTime: df.ModTime(), FileMode: df.Mode(), IsDir: df.IsDir(), IsSymlink: isSymlink, IsHidden: file.IsHidden(fPath), Extension: filepath.Ext(name), Path: fPath, Mode: fmt.Sprintf("%04o", df.Mode().Perm()), } if isSymlink { fileInfo.LinkPath = file.GetSymlink(fPath) } if df.Size() > 0 { fileInfo.MimeType = file.GetMimeType(fPath) } if isInvalidLink { fileInfo.Type = "invalid_link" } items = append(items, fileInfo) } if containSub { f.ItemTotal = total } start := (page - 1) * pageSize end := pageSize + start var result []*FileInfo if start < 0 || start > f.ItemTotal || end < 0 || start > end { result = items } else { if end > f.ItemTotal { result = items[start:] } else { result = items[start:end] } } f.Items = result return nil } func getContent(f *FileInfo) error { if f.Size <= 10*1024*1024 { afs := &afero.Afero{Fs: f.Fs} cByte, err := afs.ReadFile(f.Path) if err != nil { return nil } if len(cByte) > 0 && detectBinary(cByte) { return errors.New("ErrFileCanNotRead") } f.Content = string(cByte) return nil } else { return errors.New("ErrFileCanNotRead") } } func detectBinary(buf []byte) bool { whiteByte := 0 n := 1024 if len(buf) < 1024 { n = len(buf) } for i := 0; i < n; i++ { if (buf[i] >= 0x20) || buf[i] == 9 || buf[i] == 10 || buf[i] == 13 { whiteByte++ } else if buf[i] <= 6 || (buf[i] >= 14 && buf[i] <= 31) { return true } } return whiteByte < 1 }