ziptil.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. package ziptil
  2. import (
  3. "archive/zip"
  4. "fmt"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. )
  10. //解压zip文件
  11. //@param zipFile 需要解压的zip文件
  12. //@param dest 需要解压到的目录
  13. //@return err 返回错误
  14. func Unzip(zipFile, dest string) (err error) {
  15. dest = strings.TrimSuffix(dest, "/") + "/" // Make sure suffix with "/".
  16. // 打开一个zip格式文件
  17. r, err := zip.OpenReader(zipFile)
  18. if err != nil {
  19. return err
  20. }
  21. defer r.Close()
  22. // 迭代压缩文件中的文件,打印出文件中的内容
  23. for _, f := range r.File {
  24. if !f.FileInfo().IsDir() {
  25. path := filepath.Join(dest, f.Name)
  26. // logs.Debug("file name: ", f.Name, ",dest:", dest,
  27. // ",absolute path: ", filepath.Join(dest, f.Name),
  28. // ",absolute dir: ", filepath.Dir(path),
  29. // ",relative dir: ", filepath.Dir(f.Name))
  30. if dir := filepath.Dir(path); !strings.Contains(dir, "__MACOSX") {
  31. // This branch : 非目录,且不包含__MACOSX目录
  32. /* Resolve the Zip Slip problem.(Solution: The decompressed file must be in the DEST directory.)
  33. References: https://github.com/golang/go/issues/25849
  34. https://github.com/mholt/archiver/blob/e4ef56d48eb029648b0e895bb0b6a393ef0829c3/archiver.go#L110-L119 */
  35. if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
  36. return fmt.Errorf("illegal file path: %s", path)
  37. }
  38. os.MkdirAll(dir, 0777)
  39. if fcreate, err := os.Create(path); err == nil {
  40. if rc, err := f.Open(); err == nil {
  41. io.Copy(fcreate, rc)
  42. rc.Close() //不要用defer来关闭,如果文件太多的话,会报too many open files 的错误
  43. fcreate.Close()
  44. } else {
  45. fcreate.Close()
  46. return err
  47. }
  48. } else {
  49. return err
  50. }
  51. }
  52. }
  53. }
  54. return nil
  55. }
  56. //压缩文件
  57. func Zip(source, target string) error {
  58. zipFile, err := os.Create(target)
  59. if err != nil {
  60. return err
  61. }
  62. defer zipFile.Close()
  63. archive := zip.NewWriter(zipFile)
  64. defer archive.Close()
  65. source = strings.Replace(source, "\\", "/", -1)
  66. filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
  67. if err != nil {
  68. return err
  69. }
  70. path = strings.Replace(path, "\\", "/", -1)
  71. if path == source {
  72. return nil
  73. }
  74. header, err := zip.FileInfoHeader(info)
  75. if err != nil {
  76. return err
  77. }
  78. header.Name = strings.TrimPrefix(strings.TrimPrefix(strings.Replace(path, "\\", "/", -1), source), "/")
  79. if info.IsDir() {
  80. header.Name += "/"
  81. } else {
  82. header.Method = zip.Deflate
  83. }
  84. writer, err := archive.CreateHeader(header)
  85. if err != nil {
  86. return err
  87. }
  88. if info.IsDir() {
  89. return nil
  90. }
  91. file, err := os.Open(path)
  92. if err != nil {
  93. return err
  94. }
  95. defer file.Close()
  96. _, err = io.Copy(writer, file)
  97. return err
  98. })
  99. return err
  100. }
  101. ////压缩指定文件或文件夹
  102. ////@param dest 压缩后的zip文件目标,如/usr/local/hello.zip
  103. ////@param filepath 需要压缩的文件或者文件夹
  104. ////@return err 错误。如果返回错误,则会删除dest文件
  105. //func Zip(dest string, filepath ...string) (err error) {
  106. // if len(filepath) == 0 {
  107. // return errors.New("lack of file")
  108. // }
  109. // //创建文件
  110. // fzip, err := os.Create(dest)
  111. // if err != nil {
  112. // return err
  113. // }
  114. // defer fzip.Close()
  115. //
  116. // var filelist []filetil.FileList
  117. // for _, file := range filepath {
  118. // if info, err := os.Stat(file); err == nil {
  119. // if info.IsDir() { //目录,则扫描文件
  120. // if f, _ := filetil.ScanFiles(file); len(f) > 0 {
  121. // filelist = append(filelist, f...)
  122. // }
  123. // } else { //文件
  124. // filelist = append(filelist, filetil.FileList{
  125. // IsDir: false,
  126. // Name: info.Name(),
  127. // Path: file,
  128. // })
  129. // }
  130. // } else {
  131. // return err
  132. // }
  133. // }
  134. // w := zip.NewWriter(fzip)
  135. // defer w.Close()
  136. // for _, file := range filelist {
  137. // if !file.IsDir {
  138. // if fw, err := w.Create(strings.TrimLeft(file.Path, "./")); err != nil {
  139. // return err
  140. // } else {
  141. // if fileContent, err := ioutil.ReadFile(file.Path); err != nil {
  142. // return err
  143. // } else {
  144. // if _, err = fw.Write(fileContent); err != nil {
  145. // return err
  146. // }
  147. // }
  148. // }
  149. // }
  150. // }
  151. // return
  152. //}
  153. func Compress(dst string, src string) (err error) {
  154. d, _ := os.Create(dst)
  155. defer d.Close()
  156. w := zip.NewWriter(d)
  157. defer w.Close()
  158. src = strings.Replace(src, "\\", "/", -1)
  159. f, err := os.Open(src)
  160. if err != nil {
  161. return err
  162. }
  163. //prefix := src[strings.LastIndex(src,"/"):]
  164. err = compress(f, "", w)
  165. if err != nil {
  166. return err
  167. }
  168. return nil
  169. }
  170. func compress(file *os.File, prefix string, zw *zip.Writer) error {
  171. info, err := file.Stat()
  172. if err != nil {
  173. return err
  174. }
  175. if info.IsDir() {
  176. if prefix != "" {
  177. prefix = prefix + "/" + info.Name()
  178. } else {
  179. prefix = info.Name()
  180. }
  181. fileInfos, err := file.Readdir(-1)
  182. if err != nil {
  183. return err
  184. }
  185. for _, fi := range fileInfos {
  186. f, err := os.Open(file.Name() + "/" + fi.Name())
  187. if err != nil {
  188. return err
  189. }
  190. err = compress(f, prefix, zw)
  191. if err != nil {
  192. return err
  193. }
  194. }
  195. } else {
  196. header, err := zip.FileInfoHeader(info)
  197. if prefix != "" {
  198. header.Name = prefix + "/" + header.Name
  199. }
  200. if err != nil {
  201. return err
  202. }
  203. writer, err := zw.CreateHeader(header)
  204. if err != nil {
  205. return err
  206. }
  207. _, err = io.Copy(writer, file)
  208. file.Close()
  209. if err != nil {
  210. return err
  211. }
  212. }
  213. return nil
  214. }