186 lines
4.0 KiB
Go
186 lines
4.0 KiB
Go
package file
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
|
|
"be.ems/src/framework/logger"
|
|
)
|
|
|
|
// transferToNewFile 读取目标文件转移到新路径下
|
|
//
|
|
// readFilePath 读取目标文件
|
|
//
|
|
// writePath 写入路径
|
|
//
|
|
// fileName 文件名称
|
|
func transferToNewFile(file *multipart.FileHeader, dst string) error {
|
|
src, err := file.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer src.Close()
|
|
|
|
if err = os.MkdirAll(filepath.Dir(dst), 0775); err != nil {
|
|
return err
|
|
}
|
|
|
|
out, err := os.Create(dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
_, err = io.Copy(out, src)
|
|
return err
|
|
}
|
|
|
|
// mergeToNewFile 将多个文件合并成一个文件并删除合并前的切片目录文件
|
|
//
|
|
// dirPath 读取要合并文件的目录
|
|
//
|
|
// writePath 写入路径
|
|
//
|
|
// fileName 文件名称
|
|
func mergeToNewFile(dirPath string, writePath string, fileName string) error {
|
|
// 读取目录下所有文件并排序,注意文件名称是否数值
|
|
fileNameList, err := getDirFileNameList(dirPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read merge target file: %v", err)
|
|
}
|
|
if len(fileNameList) <= 0 {
|
|
return fmt.Errorf("failed to read merge target file")
|
|
}
|
|
|
|
// 排序
|
|
sort.Slice(fileNameList, func(i, j int) bool {
|
|
numI, _ := strconv.Atoi(fileNameList[i])
|
|
numJ, _ := strconv.Atoi(fileNameList[j])
|
|
return numI < numJ
|
|
})
|
|
|
|
// 写入到新路径文件
|
|
newFilePath := filepath.Join(writePath, fileName)
|
|
if err = os.MkdirAll(filepath.Dir(newFilePath), 0775); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 转移完成后删除切片目录
|
|
defer os.Remove(dirPath)
|
|
|
|
// 打开新路径文件
|
|
outputFile, err := os.Create(newFilePath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create file: %v", err)
|
|
}
|
|
defer outputFile.Close()
|
|
|
|
// 逐个读取文件后进行流拷贝数据块
|
|
for _, fileName := range fileNameList {
|
|
chunkPath := filepath.Join(dirPath, fileName)
|
|
// 拷贝结束后删除切片
|
|
defer os.Remove(chunkPath)
|
|
// 打开切片文件
|
|
inputFile, err := os.Open(chunkPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open file: %v", err)
|
|
}
|
|
defer inputFile.Close()
|
|
// 拷贝文件流
|
|
_, err = io.Copy(outputFile, inputFile)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to copy file data: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// getFileSize 读取文件大小
|
|
func getFileSize(filePath string) int64 {
|
|
// 获取文件信息
|
|
fileInfo, err := os.Stat(filePath)
|
|
if err != nil {
|
|
logger.Errorf("Failed stat %s: %v", filePath, err)
|
|
return 0
|
|
}
|
|
// 获取文件大小(字节数)
|
|
return fileInfo.Size()
|
|
}
|
|
|
|
// 读取文件流用于返回下载
|
|
//
|
|
// filePath 文件路径
|
|
// startOffset, endOffset 分片块读取区间,根据文件切片的块范围
|
|
func getFileStream(filePath string, startOffset, endOffset int64) ([]byte, error) {
|
|
// 打开文件
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
// 获取文件的大小
|
|
fileInfo, err := file.Stat()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
fileSize := fileInfo.Size()
|
|
|
|
// 确保起始和结束偏移量在文件范围内
|
|
if startOffset > fileSize {
|
|
startOffset = 0
|
|
}
|
|
if endOffset >= fileSize {
|
|
endOffset = fileSize - 1
|
|
}
|
|
|
|
// 计算切片的大小
|
|
chunkSize := endOffset - startOffset + 1
|
|
|
|
// 创建 SectionReader
|
|
reader := io.NewSectionReader(file, startOffset, chunkSize)
|
|
|
|
// 创建一个缓冲区来存储读取的数据
|
|
buffer := make([]byte, chunkSize)
|
|
|
|
// 读取数据到缓冲区
|
|
_, err = reader.Read(buffer)
|
|
if err != nil && err != io.EOF {
|
|
return nil, err
|
|
}
|
|
|
|
return buffer, nil
|
|
}
|
|
|
|
// 获取文件目录下所有文件名称,不含目录名称
|
|
//
|
|
// filePath 文件路径
|
|
func getDirFileNameList(dirPath string) ([]string, error) {
|
|
fileNames := []string{}
|
|
|
|
dir, err := os.Open(dirPath)
|
|
if err != nil {
|
|
return fileNames, nil
|
|
}
|
|
defer dir.Close()
|
|
|
|
fileInfos, err := dir.Readdir(-1)
|
|
if err != nil {
|
|
return fileNames, err
|
|
}
|
|
|
|
for _, fileInfo := range fileInfos {
|
|
if fileInfo.Mode().IsRegular() {
|
|
fileNames = append(fileNames, fileInfo.Name())
|
|
}
|
|
}
|
|
|
|
return fileNames, nil
|
|
}
|