Files
be.ems/features/file/service.go

207 lines
4.2 KiB
Go

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
}