gres_func_zip.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gres
  7. import (
  8. "archive/zip"
  9. "github.com/gogf/gf/internal/fileinfo"
  10. "github.com/gogf/gf/internal/intlog"
  11. "github.com/gogf/gf/os/gfile"
  12. "io"
  13. "os"
  14. "strings"
  15. "time"
  16. )
  17. // ZipPathWriter compresses <paths> to <writer> using zip compressing algorithm.
  18. // The unnecessary parameter <prefix> indicates the path prefix for zip file.
  19. //
  20. // Note that the parameter <paths> can be either a directory or a file, which
  21. // supports multiple paths join with ','.
  22. func zipPathWriter(paths string, writer io.Writer, prefix ...string) error {
  23. zipWriter := zip.NewWriter(writer)
  24. defer zipWriter.Close()
  25. for _, path := range strings.Split(paths, ",") {
  26. path = strings.TrimSpace(path)
  27. if err := doZipPathWriter(path, "", zipWriter, prefix...); err != nil {
  28. return err
  29. }
  30. }
  31. return nil
  32. }
  33. // doZipPathWriter compresses the file of given <path> and writes the content to <zipWriter>.
  34. // The parameter <exclude> specifies the exclusive file path that is not compressed to <zipWriter>,
  35. // commonly the destination zip file path.
  36. // The unnecessary parameter <prefix> indicates the path prefix for zip file.
  37. func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix ...string) error {
  38. var (
  39. err error
  40. files []string
  41. )
  42. path, err = gfile.Search(path)
  43. if err != nil {
  44. return err
  45. }
  46. if gfile.IsDir(path) {
  47. files, err = gfile.ScanDir(path, "*", true)
  48. if err != nil {
  49. return err
  50. }
  51. } else {
  52. files = []string{path}
  53. }
  54. headerPrefix := ""
  55. if len(prefix) > 0 && prefix[0] != "" {
  56. headerPrefix = prefix[0]
  57. }
  58. headerPrefix = strings.TrimRight(headerPrefix, "\\/")
  59. if len(headerPrefix) > 0 && gfile.IsDir(path) {
  60. headerPrefix += "/"
  61. }
  62. if headerPrefix == "" {
  63. headerPrefix = gfile.Basename(path)
  64. }
  65. headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
  66. for _, file := range files {
  67. if exclude == file {
  68. intlog.Printf(`exclude file path: %s`, file)
  69. continue
  70. }
  71. err := zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter)
  72. if err != nil {
  73. return err
  74. }
  75. }
  76. // Add all directories to zip archive.
  77. if headerPrefix != "" {
  78. var name string
  79. path = headerPrefix
  80. for {
  81. name = gfile.Basename(path)
  82. err := zipFileVirtual(
  83. fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), path, zipWriter,
  84. )
  85. if err != nil {
  86. return err
  87. }
  88. if path == "/" || !strings.Contains(path, "/") {
  89. break
  90. }
  91. path = gfile.Dir(path)
  92. }
  93. }
  94. return nil
  95. }
  96. // zipFile compresses the file of given <path> and writes the content to <zw>.
  97. // The parameter <prefix> indicates the path prefix for zip file.
  98. func zipFile(path string, prefix string, zw *zip.Writer) error {
  99. prefix = strings.Replace(prefix, "//", "/", -1)
  100. file, err := os.Open(path)
  101. if err != nil {
  102. return nil
  103. }
  104. defer file.Close()
  105. info, err := file.Stat()
  106. if err != nil {
  107. return err
  108. }
  109. header, err := createFileHeader(info, prefix)
  110. if err != nil {
  111. return err
  112. }
  113. if !info.IsDir() {
  114. header.Method = zip.Deflate
  115. }
  116. writer, err := zw.CreateHeader(header)
  117. if err != nil {
  118. return err
  119. }
  120. if !info.IsDir() {
  121. if _, err = io.Copy(writer, file); err != nil {
  122. return err
  123. }
  124. }
  125. return nil
  126. }
  127. func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error {
  128. header, err := createFileHeader(info, "")
  129. if err != nil {
  130. return err
  131. }
  132. header.Name = path
  133. if _, err := zw.CreateHeader(header); err != nil {
  134. return err
  135. }
  136. return nil
  137. }
  138. func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {
  139. header, err := zip.FileInfoHeader(info)
  140. if err != nil {
  141. return nil, err
  142. }
  143. if len(prefix) > 0 {
  144. prefix = strings.Replace(prefix, `\`, `/`, -1)
  145. prefix = strings.TrimRight(prefix, `/`)
  146. header.Name = prefix + `/` + header.Name
  147. }
  148. return header, nil
  149. }