任务一完成
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
breakpointDir = "./breakpointDir/"
|
||||
finishDir = "./fileDir/"
|
||||
)
|
||||
|
||||
// BreakPointContinue 断点续传
|
||||
// content: 文件片段内容
|
||||
// fileName: 文件名
|
||||
// contentNumber: 当前片段序号
|
||||
// contentTotal: 总片段数
|
||||
// fileMd5: 文件MD5
|
||||
func BreakPointContinue(content []byte, fileName string, contentNumber int, contentTotal int, fileMd5 string) (string, error) {
|
||||
path := breakpointDir + fileMd5 + "/"
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
pathC, err := makeFileContent(content, fileName, path, contentNumber)
|
||||
return pathC, err
|
||||
}
|
||||
|
||||
// CheckMd5 检查Md5
|
||||
func CheckMd5(content []byte, chunkMd5 string) bool {
|
||||
fileMd5 := MD5V(content)
|
||||
return fileMd5 == chunkMd5
|
||||
}
|
||||
|
||||
// makeFileContent 创建切片内容
|
||||
func makeFileContent(content []byte, fileName string, FileDir string, contentNumber int) (string, error) {
|
||||
if strings.Contains(fileName, "..") || strings.Contains(FileDir, "..") {
|
||||
return "", errors.New("文件名或路径不合法")
|
||||
}
|
||||
path := FileDir + fileName + "_" + strconv.Itoa(contentNumber)
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = f.Write(content)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// MakeFile 合并切片文件
|
||||
func MakeFile(fileName string, FileMd5 string) (string, error) {
|
||||
rd, err := os.ReadDir(breakpointDir + FileMd5)
|
||||
if err != nil {
|
||||
return finishDir + fileName, err
|
||||
}
|
||||
_ = os.MkdirAll(finishDir, os.ModePerm)
|
||||
fd, err := os.OpenFile(finishDir+fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o644)
|
||||
if err != nil {
|
||||
return finishDir + fileName, err
|
||||
}
|
||||
defer fd.Close()
|
||||
for k := range rd {
|
||||
content, _ := os.ReadFile(breakpointDir + FileMd5 + "/" + fileName + "_" + strconv.Itoa(k))
|
||||
_, err = fd.Write(content)
|
||||
if err != nil {
|
||||
_ = os.Remove(finishDir + fileName)
|
||||
return finishDir + fileName, err
|
||||
}
|
||||
}
|
||||
return finishDir + fileName, nil
|
||||
}
|
||||
|
||||
// RemoveChunk 移除切片
|
||||
func RemoveChunk(FileMd5 string) error {
|
||||
return os.RemoveAll(breakpointDir + FileMd5)
|
||||
}
|
||||
|
||||
// GetBreakpointDir 获取断点续传目录
|
||||
func GetBreakpointDir() string {
|
||||
return breakpointDir
|
||||
}
|
||||
|
||||
// GetFinishDir 获取完成文件目录
|
||||
func GetFinishDir() string {
|
||||
return finishDir
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"strconv"
|
||||
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
||||
// GetColumnName 获取Excel列名 (1->A, 2->B, ..., 27->AA)
|
||||
func GetColumnName(n int) string {
|
||||
columnName := ""
|
||||
for n > 0 {
|
||||
n--
|
||||
columnName = string(rune('A'+n%26)) + columnName
|
||||
n /= 26
|
||||
}
|
||||
return columnName
|
||||
}
|
||||
|
||||
// CreateExcelFile 创建Excel文件
|
||||
func CreateExcelFile() *excelize.File {
|
||||
return excelize.NewFile()
|
||||
}
|
||||
|
||||
// OpenExcelFile 打开Excel文件
|
||||
func OpenExcelFile(file *multipart.FileHeader) (*excelize.File, error) {
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer src.Close()
|
||||
return excelize.OpenReader(src)
|
||||
}
|
||||
|
||||
// WriteExcelRows 写入Excel行数据
|
||||
func WriteExcelRows(f *excelize.File, sheetName string, rows [][]interface{}) error {
|
||||
for i, row := range rows {
|
||||
for j, cell := range row {
|
||||
cellName := fmt.Sprintf("%s%d", GetColumnName(j+1), i+1)
|
||||
if err := f.SetCellValue(sheetName, cellName, cell); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteExcelRow 写入单行数据
|
||||
func WriteExcelRow(f *excelize.File, sheetName string, rowIndex int, row []interface{}) error {
|
||||
for j, cell := range row {
|
||||
cellName := fmt.Sprintf("%s%d", GetColumnName(j+1), rowIndex)
|
||||
if err := f.SetCellValue(sheetName, cellName, cell); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExcelToBuffer 将Excel文件写入Buffer
|
||||
func ExcelToBuffer(f *excelize.File) (*bytes.Buffer, error) {
|
||||
return f.WriteToBuffer()
|
||||
}
|
||||
|
||||
// ReadExcelRows 读取Excel所有行
|
||||
func ReadExcelRows(f *excelize.File, sheetName string) ([][]string, error) {
|
||||
return f.GetRows(sheetName)
|
||||
}
|
||||
|
||||
// SetCellValueAuto 自动类型设置单元格值
|
||||
func SetCellValueAuto(f *excelize.File, sheetName, cell string, value string) error {
|
||||
// 尝试解析为数字
|
||||
if v, err := strconv.ParseFloat(value, 64); err == nil {
|
||||
return f.SetCellValue(sheetName, cell, v)
|
||||
}
|
||||
if v, err := strconv.ParseInt(value, 10, 64); err == nil {
|
||||
return f.SetCellValue(sheetName, cell, v)
|
||||
}
|
||||
return f.SetCellValue(sheetName, cell, value)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// MD5V 计算字节数组的MD5值
|
||||
func MD5V(data []byte) string {
|
||||
h := md5.New()
|
||||
h.Write(data)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// MD5String 计算字符串的MD5值
|
||||
func MD5String(s string) string {
|
||||
return MD5V([]byte(s))
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ZipFiles 压缩文件
|
||||
func ZipFiles(filename string, files []string, oldForm, newForm string) error {
|
||||
newZipFile, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer newZipFile.Close()
|
||||
|
||||
zipWriter := zip.NewWriter(newZipFile)
|
||||
defer zipWriter.Close()
|
||||
|
||||
for _, file := range files {
|
||||
if err = addFileToZip(zipWriter, file, oldForm, newForm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addFileToZip(zipWriter *zip.Writer, filename, oldForm, newForm string) error {
|
||||
fileToZip, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileToZip.Close()
|
||||
|
||||
info, err := fileToZip.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header.Name = strings.Replace(filename, oldForm, newForm, 1)
|
||||
header.Method = zip.Deflate
|
||||
|
||||
writer, err := zipWriter.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(writer, fileToZip)
|
||||
return err
|
||||
}
|
||||
|
||||
// Unzip 解压文件
|
||||
func Unzip(src, dest string) ([]string, error) {
|
||||
var filenames []string
|
||||
|
||||
r, err := zip.OpenReader(src)
|
||||
if err != nil {
|
||||
return filenames, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
for _, f := range r.File {
|
||||
fpath := filepath.Join(dest, f.Name)
|
||||
|
||||
// 安全检查:防止路径遍历攻击
|
||||
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
|
||||
continue
|
||||
}
|
||||
|
||||
filenames = append(filenames, fpath)
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(fpath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
|
||||
return filenames, err
|
||||
}
|
||||
|
||||
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
return filenames, err
|
||||
}
|
||||
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
outFile.Close()
|
||||
return filenames, err
|
||||
}
|
||||
|
||||
_, err = io.Copy(outFile, rc)
|
||||
outFile.Close()
|
||||
rc.Close()
|
||||
|
||||
if err != nil {
|
||||
return filenames, err
|
||||
}
|
||||
}
|
||||
return filenames, nil
|
||||
}
|
||||
Reference in New Issue
Block a user