upload.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package file
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "icloudapp.cn/tools/util"
  6. "io"
  7. "mime/multipart"
  8. "os"
  9. "path"
  10. "strconv"
  11. "strings"
  12. "time"
  13. )
  14. type Upload struct {
  15. Path string
  16. Allowed map[string]bool
  17. HasHash bool
  18. }
  19. // FileWithErr 用于返回一组上传的文件信息
  20. type FileWithErr struct {
  21. Err error
  22. FileInfo *File
  23. }
  24. type File struct {
  25. //上传文件名
  26. Name string `json:"name"`
  27. //上传后文件路径
  28. File string `json:"file"`
  29. Basename string `json:"basename"`
  30. //文件大小
  31. Size int64 `json:"size"`
  32. //文件Hash
  33. Hash string `json:"hash"`
  34. //文件类型
  35. Mine string `json:"mine"`
  36. }
  37. func NewUpload(dir string) *Upload {
  38. return &Upload{
  39. Path: dir,
  40. }
  41. }
  42. // 是否返回文件的hash
  43. func (u *Upload) SetHasHash(hashash bool) {
  44. u.HasHash = hashash
  45. }
  46. // 设置上传目录
  47. func (u *Upload) SetUploadPath(dir string) {
  48. u.Path = dir
  49. }
  50. // 设置允许的文件类型
  51. func (u *Upload) SetAllowed(allowed map[string]bool) {
  52. u.Allowed = allowed
  53. }
  54. // 追加允许的文件类型
  55. func (u *Upload) AppendAllow(ext string) {
  56. u.Allowed[ext] = true
  57. }
  58. // 上传单个文件
  59. func (u *Upload) Single(file multipart.FileHeader) (*File, error) {
  60. res := &File{}
  61. extName := strings.ToLower(path.Ext(file.Filename))
  62. if _, ok := u.Allowed[extName]; !ok {
  63. return res, util.NewError("不允许的上传类型")
  64. }
  65. res.Name = file.Filename
  66. res.Size = file.Size
  67. res.Mine = file.Header.Get("Content-Type")
  68. if !IsDir(u.Path) {
  69. if err := os.MkdirAll(u.Path, 0750); err != nil {
  70. return nil, util.NewError("目录创建失败", u.Path)
  71. }
  72. }
  73. fileUnixName := strconv.FormatInt(time.Now().UnixNano(), 10)
  74. res.Basename = fileUnixName + extName
  75. savePath := path.Join(u.Path, res.Basename)
  76. res.File = savePath
  77. src, err := file.Open()
  78. if err != nil {
  79. return nil, util.NewError("文件打开失败:", err.Error())
  80. }
  81. defer src.Close()
  82. out, err := os.Create(savePath)
  83. if err != nil {
  84. return nil, util.NewError("文件创建失败:", err.Error())
  85. }
  86. defer out.Close()
  87. if u.HasHash {
  88. res.Hash = u.FileHash(savePath)
  89. }
  90. _, err = io.Copy(out, src)
  91. return res, nil
  92. }
  93. // Multiple 上传多个文件
  94. func (u *Upload) Multiple(files []multipart.FileHeader) ([]*FileWithErr, error) {
  95. var res []*FileWithErr
  96. for key, file := range files {
  97. uploaded, err := u.Single(file)
  98. res[key] = &FileWithErr{Err: err, FileInfo: uploaded}
  99. }
  100. return res, nil
  101. }
  102. // FileHash 获取文件的hash值
  103. func (u *Upload) FileHash(path string) string {
  104. file, _ := os.Open(path)
  105. m := md5.New()
  106. _, err := io.Copy(m, file)
  107. if err == nil {
  108. hash := m.Sum(nil)
  109. return hex.EncodeToString(hash)
  110. }
  111. return ""
  112. }