feat: 文件备份/CDR/LOG本地文件列表功能接口

This commit is contained in:
TsMask
2025-05-09 18:31:23 +08:00
parent 5e7c9bb7e0
commit 2f27466408
15 changed files with 1287 additions and 73 deletions

View File

@@ -152,3 +152,112 @@ func WriteSheet(headerCells map[string]string, dataCells []map[string]any, fileN
}
return saveFilePath, nil
}
// WriterFileExecl 写入xlsx文件
//
// 例如:
// headerCells := map[string]string{"A1": "姓名", "B1": "年龄", "C1": "城市"}
//
// dataCells := []map[string]any{
// {"A2": "1", "B2": "2", "C2": "3"},
// }
//
// filePath := "example.xlsx"
// err := file.WriterFileExecl(headerCells, dataCells, filePath, "Sheet1")
func WriterFileExecl(headerCells map[string]string, dataCells []map[string]any, filePath, sheetName string) error {
f := excelize.NewFile()
defer func() {
if err := f.Close(); err != nil {
logger.Errorf("WriterFileExecl to close worksheet file: %v", err)
}
}()
// 创建一个工作表
if sheetName == "" {
sheetName = "Sheet1"
}
index, err := f.NewSheet(sheetName)
if err != nil {
return fmt.Errorf("failed to create worksheet %v", err)
}
// 设置工作簿的默认工作表
f.SetActiveSheet(index)
// 首个和最后key名称
firstKey := "A"
lastKey := "B"
// 第一行表头标题
for key, title := range headerCells {
f.SetCellValue(sheetName, key, title)
if key[:1] > lastKey {
lastKey = key[:1]
}
}
// 设置工作表上宽度为 20
f.SetColWidth(sheetName, firstKey, lastKey, 20)
// 从第二行开始的数据
for _, cell := range dataCells {
for key, value := range cell {
f.SetCellValue(sheetName, key, value)
}
}
// 创建文件目录
if err := os.MkdirAll(filepath.Dir(filePath), 0775); err != nil {
return fmt.Errorf("failed to create save file %v", err)
}
// 根据指定路径保存文件
if err := f.SaveAs(filePath); err != nil {
return fmt.Errorf("failed to save worksheet %v", err)
}
return nil
}
// ReadFileExecl 读取xlsx文件 转换数组数据
func ReadFileExecl(filePath, sheetName string) ([]map[string]string, error) {
data := make([]map[string]string, 0)
// 打开 Excel 文件
f, err := excelize.OpenFile(filePath)
if err != nil {
return data, err
}
defer func() {
if err := f.Close(); err != nil {
logger.Errorf("ReadSheet to close worksheet file : %v", err)
}
}()
// 检查工作簿是否存在
if sheetName == "" {
sheetName = "Sheet1"
}
if visible, _ := f.GetSheetVisible(sheetName); !visible {
return data, fmt.Errorf("failed to read workbook %s", sheetName)
}
// 获取工作簿记录
rows, err := f.GetRows(sheetName)
if err != nil {
return data, err
}
for i, row := range rows {
// 跳过第一行
if i == 0 {
continue
}
// 遍历每个单元格
rowData := map[string]string{}
for columnIndex, cellValue := range row {
columnName, _ := excelize.ColumnNumberToName(columnIndex + 1)
rowData[columnName] = cellValue
}
data = append(data, rowData)
}
return data, nil
}

View File

@@ -12,7 +12,7 @@ import (
"time"
"be.ems/src/framework/config"
"be.ems/src/framework/constants/uploadsubpath"
"be.ems/src/framework/constants"
"be.ems/src/framework/logger"
"be.ems/src/framework/utils/date"
"be.ems/src/framework/utils/generate"
@@ -237,7 +237,7 @@ func TransferChunkUploadFile(file *multipart.FileHeader, index, identifier strin
// 上传资源路径
prefix, dir := resourceUpload()
// 新文件名称并组装文件地址
filePath := filepath.Join(uploadsubpath.CHUNK, date.ParseDatePath(time.Now()), identifier)
filePath := filepath.Join(constants.UPLOAD_CHUNK, date.ParseDatePath(time.Now()), identifier)
writePathFile := filepath.Join(dir, filePath, index)
// 存入新文件路径
err = transferToNewFile(file, writePathFile)
@@ -261,7 +261,7 @@ func ChunkCheckFile(identifier, originalFileName string) ([]string, error) {
}
// 上传资源路径
_, dir := resourceUpload()
dirPath := path.Join(uploadsubpath.CHUNK, date.ParseDatePath(time.Now()), identifier)
dirPath := path.Join(constants.UPLOAD_CHUNK, date.ParseDatePath(time.Now()), identifier)
readPath := path.Join(dir, dirPath)
fileList, err := getDirFileNameList(readPath)
if err != nil {
@@ -286,7 +286,7 @@ func ChunkMergeFile(identifier, originalFileName, subPath string) (string, error
// 上传资源路径
prefix, dir := resourceUpload()
// 切片存放目录
dirPath := path.Join(uploadsubpath.CHUNK, date.ParseDatePath(time.Now()), identifier)
dirPath := path.Join(constants.UPLOAD_CHUNK, date.ParseDatePath(time.Now()), identifier)
readPath := path.Join(dir, dirPath)
// 组合存放文件路径
fileName := generateFileName(originalFileName)

View File

@@ -0,0 +1,78 @@
package file
import (
"os"
"path/filepath"
)
// FileListRow 文件列表行数据
type FileListRow struct {
FileType string `json:"fileType"` // 文件类型 dir, file, symlink
FileMode string `json:"fileMode"` // 文件的权限
LinkCount int64 `json:"linkCount"` // 硬链接数目
Owner string `json:"owner"` // 所属用户
Group string `json:"group"` // 所属组
Size int64 `json:"size"` // 文件的大小
ModifiedTime int64 `json:"modifiedTime"` // 最后修改时间,单位为秒
FileName string `json:"fileName"` // 文件的名称
}
// 文件列表
// search 文件名后模糊*
//
// return 行记录,异常
func FileList(path, search string) ([]FileListRow, error) {
var rows []FileListRow
// 构建搜索模式
pattern := "*"
if search != "" {
pattern = search + pattern
}
// 读取目录内容
entries, err := os.ReadDir(path)
if err != nil {
return nil, err
}
// 遍历目录项
for _, entry := range entries {
// 匹配文件名
matched, err := filepath.Match(pattern, entry.Name())
if err != nil || !matched {
continue
}
// 获取文件详细信息
info, err := entry.Info()
if err != nil {
continue
}
// 确定文件类型
fileType := "file"
if info.IsDir() {
fileType = "dir"
} else if info.Mode()&os.ModeSymlink != 0 {
fileType = "symlink"
}
// 获取系统特定的文件信息
linkCount, owner, group := getFileInfo(info)
// 组装文件信息
rows = append(rows, FileListRow{
FileMode: info.Mode().String(),
FileType: fileType,
LinkCount: linkCount,
Owner: owner,
Group: group,
Size: info.Size(),
ModifiedTime: info.ModTime().UnixMilli(),
FileName: entry.Name(),
})
}
return rows, nil
}

View File

@@ -0,0 +1,36 @@
//go:build !windows
// +build !windows
package file
import (
"fmt"
"os"
"os/user"
"syscall"
)
// getFileInfo 获取系统特定的文件信息s
func getFileInfo(info os.FileInfo) (linkCount int64, owner, group string) {
// Unix-like 系统 (Linux, macOS)
if stat, ok := info.Sys().(*syscall.Stat_t); ok {
// 获取用户名
ownerName := "root"
if stat.Uid != 0 {
if u, err := user.LookupId(fmt.Sprint(stat.Uid)); err == nil {
ownerName = u.Username
}
}
// 获取组名
groupName := "root"
if stat.Gid != 0 {
if g, err := user.LookupGroupId(fmt.Sprint(stat.Gid)); err == nil {
groupName = g.Name
}
}
return int64(stat.Nlink), ownerName, groupName
}
return 1, "", ""
}

View File

@@ -0,0 +1,13 @@
//go:build windows
// +build windows
package file
import (
"os"
)
// getFileInfo 获取系统特定的文件信息
func getFileInfo(_ os.FileInfo) (linkCount int64, owner, group string) {
return 1, "Administrator", "Administrators"
}