add: 提交

This commit is contained in:
lichang
2023-08-14 17:02:50 +08:00
parent 897d45d443
commit 5ac2e981ea
163 changed files with 29466 additions and 0 deletions

356
lib/services/file.go Normal file
View File

@@ -0,0 +1,356 @@
package services
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"strconv"
"strings"
"ems.agt/lib/log"
)
const (
RootPath = "uploads/"
ChunkRootPath = "uploads_tmp/"
)
var (
// FilesMax 限制上传文件的大小为7 MB
FilesMax int64 = 32 << 20
// ValuesMax 限制POST字段内容的大小
ValuesMax int64 = 512
)
func GetPostFile(w http.ResponseWriter, r *http.Request) {
//获取文件流,第三个返回值是错误对象
file, header, _ := r.FormFile("file")
//读取文件流为[]byte
b, err := ioutil.ReadAll(file)
if err != nil {
log.Error("Failed to ReadAll:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
//把文件保存到指定位置
err = ioutil.WriteFile("./upload/test.zip", b, 0644)
if err != nil {
log.Error("Failed to WriteFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
//输出上传时文件名
log.Debug("filename:", header.Filename)
}
func GetUploadFile(w http.ResponseWriter, r *http.Request) {
log.Debug("GetUploadFile processing...")
file, err := os.Create("./test.zip")
if err != nil {
log.Error("Failed to Create:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
_, err = io.Copy(file, r.Body)
if err != nil {
log.Error("Failed to Copy:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
}
func GetUploadFormFile(w http.ResponseWriter, r *http.Request) {
// 设置最大的内存限制为32MB
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("file")
if err != nil {
log.Error("Failed to FormFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
defer file.Close()
log.Debug("Header:%v", handler.Header)
f, err := os.OpenFile("./"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
log.Error("Failed to OpenFile:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
defer f.Close()
_, err = io.Copy(f, file)
if err != nil {
log.Error("Failed to Copy:", err)
ResponseInternalServerError500ProcessError(w, err)
return
}
log.Debug("File uploaded successfully:", handler.Filename)
}
func HandleUploadFile(r *http.Request, path, newFileName string) (string, error) {
var filePath, fileName string
reader, err := r.MultipartReader()
if err != nil {
log.Error("Failed to MultipartReader:", err)
return "", err
}
for {
part, err := reader.NextPart()
if err == io.EOF {
break
} else if err != nil {
log.Error("Failed to NextPart:", err)
return "", err
}
log.Debugf("FileName=[%s], FormName=[%s]", part.FileName(), part.FormName())
if part.FileName() == "" { // this is FormData
data, _ := ioutil.ReadAll(part)
log.Debugf("FormData=[%s]", string(data))
} else { // This is FileData
if newFileName != "" {
fileName = newFileName
} else {
fileName = part.FileName()
}
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
log.Error("Failed to Mkdir:", err)
return "", err
}
filePath = path + "/" + fileName
file, err := os.Create(filePath)
if err != nil {
log.Error("Failed to Create:", err)
return "", err
}
defer file.Close()
_, err = io.Copy(file, part)
if err != nil {
log.Error("Failed to Copy:", err)
return "", err
}
}
}
return fileName, nil
}
func HandleUploadFormFile(w http.ResponseWriter, r *http.Request) {
r.ParseMultipartForm(32 << 20)
//mForm := r.MultipartForm
for k, _ := range r.MultipartForm.File {
// k is the key of file part
file, fileHeader, err := r.FormFile(k)
if err != nil {
fmt.Println("inovke FormFile error:", err)
return
}
defer file.Close()
fmt.Printf("the uploaded file: name[%s], size[%d], header[%#v]\n",
fileHeader.Filename, fileHeader.Size, fileHeader.Header)
// store uploaded file into local path
localFileName := "./upload/" + fileHeader.Filename
out, err := os.Create(localFileName)
if err != nil {
fmt.Printf("failed to open the file %s for writing", localFileName)
return
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
fmt.Printf("copy file err:%s\n", err)
return
}
fmt.Printf("file %s uploaded ok\n", fileHeader.Filename)
}
}
func PostFileHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("PostFileHandler processing... ")
if !strings.Contains(r.Header.Get("Content-Type"), "multipart/form-data") {
// 不支持的 Content-Type 类型
fmt.Println("Invalid Content-Type: ", r.Header.Get("Content-Type"))
http.Error(w, " 不支持的 Content-Type 类型", http.StatusBadRequest)
return
}
// 整个请求的主体大小设置为7.5Mb
r.Body = http.MaxBytesReader(w, r.Body, FilesMax+ValuesMax)
reader, err := r.MultipartReader()
if err != nil {
fmt.Println(err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
for {
// A Part represents a single part in a multipart body.
part, err := reader.NextPart()
if err != nil {
if err == io.EOF {
break
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fileName := part.FileName()
formName := part.FormName()
var buf = &bytes.Buffer{}
// 非文件字段部分大小限制验证非文件字段go中filename会是空
if fileName == "" {
var limitError = "请求主体中非文件字段" + formName + "超出大小限制"
err = uploadSizeLimit(buf, part, ValuesMax, limitError)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
continue
}
// 文件字段部分大小限制验证
var limitError = "请求主体中文件字段" + fileName + "超出大小限制"
err = uploadSizeLimit(buf, part, FilesMax, limitError)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 文件创建部分
if err := uploadFileHandle(r.Header, fileName, buf); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// 非逻辑内容,仅为测试使用
var chunkNumber = r.Header.Get("chunk-number")
if chunkNumber == "" {
http.Error(w, "文件"+fileName+"上传成功", http.StatusOK)
} else {
http.Error(w, "分片文件"+fileName+chunkNumber+"上传成功", http.StatusOK)
}
}
return
http.NotFound(w, r)
}
// 上传内容大小限制
func uploadSizeLimit(buf *bytes.Buffer, part *multipart.Part, maxLimit int64, limitError string) error {
n, err := io.CopyN(buf, part, maxLimit+1)
if err != nil && err != io.EOF {
fmt.Println("PostFileHandler:", err)
return err
}
maxLimit -= n
if maxLimit < 0 {
return errors.New(limitError)
}
return nil
}
// uploadFileHandle handle upload file
func uploadFileHandle(header http.Header, fileName string, buf *bytes.Buffer) error {
var chunkNumberStr = header.Get("chunk-number")
// 1.普通文件上传处理
if chunkNumberStr == "" {
//创建文件并写入文件内容
return createFile(RootPath+fileName, buf.Bytes())
}
// 2.分片文件上传处理
//2.1读取分片编号
chunkNumber, err := strconv.Atoi(chunkNumberStr)
if err != nil {
return err
}
//2.2创建分片文件并写入分片内容
if err := createFile(fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", chunkNumber), buf.Bytes()); err != nil {
return err
}
//2.3确认是否上传完毕
if header.Get("chunk-final") == "true" {
//2.4合并文件
if err := mergeChunkFiles(fileName); err != nil {
return err
}
//2.5删除分片
for i := 0; ; i++ {
chunFileName := fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", i)
err := os.Remove(chunFileName)
if err != nil {
if os.IsNotExist(err) {
break
}
return err
}
}
}
return nil
}
// 创建文件并写入内容
func createFile(fileName string, res []byte) error {
newFile, err := os.Create(fileName)
if err != nil {
return err
}
defer func() {
_ = newFile.Close()
}()
bufferedWriter := bufio.NewWriter(newFile)
_, err = bufferedWriter.Write(res)
if err != nil && err != io.EOF {
return err
}
return bufferedWriter.Flush()
}
// 合并分片文件
func mergeChunkFiles(fileName string) error {
var (
n int64
err error
)
finalFile, err := os.Create(RootPath + fileName)
if err != nil {
return err
}
defer finalFile.Close()
// 将分片内容写入最终文件
for i := 0; ; i++ {
chunFile, err := os.Open(fmt.Sprintf(ChunkRootPath+fileName+"%d.chunk", i))
if err != nil {
if os.IsNotExist(err) {
break
}
return err
}
n, err = io.Copy(finalFile, chunFile)
if err != nil {
return err
}
err = chunFile.Close()
if err != nil {
return err
}
if n < 1 {
break
}
}
return nil
}