193 lines
4.4 KiB
Go
193 lines
4.4 KiB
Go
package filesystem
|
||
|
||
import (
|
||
"archive/zip"
|
||
"context"
|
||
model "github.com/HFO4/cloudreve/models"
|
||
"github.com/HFO4/cloudreve/pkg/util"
|
||
"io"
|
||
"net/http"
|
||
"os"
|
||
)
|
||
|
||
/* ===============
|
||
压缩/解压缩
|
||
===============
|
||
*/
|
||
|
||
// Compress 创建给定目录和文件的压缩文件
|
||
func (fs *FileSystem) Compress(ctx context.Context, folderIDs, fileIDs []uint, writer http.ResponseWriter) error {
|
||
// 查找待压缩目录
|
||
folders, err := model.GetFoldersByIDs(folderIDs, fs.User.ID)
|
||
if err != nil && len(folders) != 0 {
|
||
return ErrDBListObjects
|
||
}
|
||
// 查找待压缩文件
|
||
files, err := model.GetFilesByIDs(fileIDs, fs.User.ID)
|
||
if err != nil && len(files) != 0 {
|
||
return ErrDBListObjects
|
||
}
|
||
|
||
// 将顶级待处理对象的路径设为根路径
|
||
for i := 0; i < len(folders); i++ {
|
||
folders[i].Position = ""
|
||
}
|
||
for i := 0; i < len(files); i++ {
|
||
files[i].Position = ""
|
||
}
|
||
|
||
// 创建压缩文件
|
||
zipFile, err := os.Create("temp/archive.zip")
|
||
if err != nil {
|
||
util.Log().Warning("%s", err)
|
||
return err
|
||
}
|
||
defer zipFile.Close()
|
||
|
||
//writer.Header().Set("Content-Type", "application/zip")
|
||
//writer.Header().Set("Content-Disposition", "attachment; filename=\"archive.zip\"")
|
||
|
||
zipWriter := zip.NewWriter(writer)
|
||
defer zipWriter.Close()
|
||
|
||
ctx, _ = context.WithCancel(context.Background())
|
||
// 压缩各个目录及文件
|
||
for i := 0; i < len(folders); i++ {
|
||
fs.doCompress(ctx, nil, &folders[i], zipWriter)
|
||
}
|
||
for i := 0; i < len(files); i++ {
|
||
fs.doCompress(ctx, &files[i], nil, zipWriter)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (fs *FileSystem) doCompress(ctx context.Context, file *model.File, folder *model.Folder, zipWriter *zip.Writer) {
|
||
// 如果对象是文件
|
||
if file != nil {
|
||
// 切换上传策略
|
||
fs.Policy = file.GetPolicy()
|
||
err := fs.dispatchHandler()
|
||
if err != nil {
|
||
util.Log().Warning("无法压缩文件%s,%s", file.Name, err)
|
||
return
|
||
}
|
||
|
||
fileToZip, err := fs.Handler.Get(ctx, file.SourceName)
|
||
if err != nil {
|
||
util.Log().Debug("Open%s,%s", file.Name, err)
|
||
return
|
||
}
|
||
if closer, ok := fileToZip.(io.Closer); ok {
|
||
defer closer.Close()
|
||
}
|
||
|
||
header := &zip.FileHeader{
|
||
Name: file.Name,
|
||
}
|
||
|
||
writer, err := zipWriter.CreateHeader(header)
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
_, err = io.Copy(writer, fileToZip)
|
||
util.Log().Debug("开始压缩%s", file.Name)
|
||
|
||
//f, err := os.Open(file.SourceName)
|
||
//if err != nil {
|
||
// util.Log().Debug("Open%s,%s", file.Name, err)
|
||
// return
|
||
//}
|
||
//
|
||
//info, err := f.Stat()
|
||
//if err != nil {
|
||
// util.Log().Debug("Stat%s,%s", file.Name, err)
|
||
// return
|
||
//}
|
||
//
|
||
//header, err := zip.FileInfoHeader(info)
|
||
//if err != nil {
|
||
// util.Log().Debug("header%s,%s", file.Name, err)
|
||
// return
|
||
//}
|
||
//
|
||
//writer, err := zipWriter.CreateHeader(header)
|
||
//if err != nil {
|
||
// util.Log().Debug("压缩出错%s,%s", header.Name, err)
|
||
// return
|
||
//}
|
||
//
|
||
//_, err = io.Copy(writer, f)
|
||
//if err != nil {
|
||
// util.Log().Debug("压缩出错%s,%s", header.Name, err)
|
||
// return
|
||
//}
|
||
//
|
||
//if true {
|
||
// f.Close()
|
||
//}
|
||
//
|
||
//util.Log().Debug("压缩完成%s", header.Name)
|
||
|
||
//pool.Submit(compressJob)
|
||
}
|
||
}
|
||
|
||
// ZipFiles compresses one or many files into a single zip archive file.
|
||
// Param 1: filename is the output zip file's name.
|
||
// Param 2: files is a list of files to add to the zip.
|
||
func ZipFiles(filename string, files []string) error {
|
||
|
||
newZipFile, err := os.Create(filename)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer newZipFile.Close()
|
||
|
||
zipWriter := zip.NewWriter(newZipFile)
|
||
defer zipWriter.Close()
|
||
|
||
// Add files to zip
|
||
for _, file := range files {
|
||
if err = AddFileToZip(zipWriter, file); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func AddFileToZip(zipWriter *zip.Writer, filename string) error {
|
||
|
||
fileToZip, err := os.Open(filename)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer fileToZip.Close()
|
||
|
||
// Get the file information
|
||
info, err := fileToZip.Stat()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
header, err := zip.FileInfoHeader(info)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// Using FileInfoHeader() above only uses the basename of the file. If we want
|
||
// to preserve the folder structure we can overwrite this with the full path.
|
||
header.Name = filename
|
||
|
||
// Change to deflate to gain better compression
|
||
// see http://golang.org/pkg/archive/zip/#pkg-constants
|
||
header.Method = zip.Deflate
|
||
|
||
writer, err := zipWriter.CreateHeader(header)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
_, err = io.Copy(writer, fileToZip)
|
||
return err
|
||
}
|