Feat: zip create
This commit is contained in:
parent
d58898e364
commit
012281c41f
5 changed files with 209 additions and 21 deletions
|
@ -1,16 +1,193 @@
|
||||||
package filesystem
|
package filesystem
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/zip"
|
||||||
"context"
|
"context"
|
||||||
|
model "github.com/HFO4/cloudreve/models"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
/* ==============
|
/* ===============
|
||||||
压缩/解压缩
|
压缩/解压缩
|
||||||
==============
|
===============
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Compress 创建给定目录和文件的压缩文件
|
// Compress 创建给定目录和文件的压缩文件
|
||||||
func (fs *FileSystem) Compress(ctx context.Context, dirs, files []uint) (io.ReadSeeker, error) {
|
func (fs *FileSystem) Compress(ctx context.Context, folderIDs, fileIDs []uint, writer http.ResponseWriter) error {
|
||||||
return nil, nil
|
// 查找待压缩目录
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,11 +77,11 @@ func (pool *Pool) Schedule() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait 等待队列中所有任务完成或有Job返回错误中止
|
// Wait 等待队列中所有任务完成或有Job返回错误中止
|
||||||
func (pool *Pool) Wait() {
|
func (pool *Pool) Wait() chan bool {
|
||||||
pool.lock.Lock()
|
pool.lock.Lock()
|
||||||
pool.waiting = true
|
pool.waiting = true
|
||||||
pool.lock.Unlock()
|
pool.lock.Unlock()
|
||||||
_ = <-pool.finishSignal
|
return pool.finishSignal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Submit 提交新任务
|
// Submit 提交新任务
|
||||||
|
@ -110,7 +110,11 @@ func (pool *Pool) start(job Job) {
|
||||||
err := job.Do()
|
err := job.Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pool.closed = true
|
pool.closed = true
|
||||||
close(pool.terminateSignal)
|
select {
|
||||||
|
case <-pool.terminateSignal:
|
||||||
|
default:
|
||||||
|
close(pool.terminateSignal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.lock.Lock()
|
pool.lock.Lock()
|
||||||
|
|
|
@ -22,13 +22,16 @@ func ArchiveAndDownload(c *gin.Context) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var service explorer.ItemService
|
var service = explorer.ItemService{
|
||||||
if err := c.ShouldBindJSON(&service); err == nil {
|
Items: []uint{117, 118, 119, 120, 121, 122, 123},
|
||||||
res := service.ArchiveAndDownload(ctx, c)
|
Dirs: []uint{},
|
||||||
c.JSON(200, res)
|
|
||||||
} else {
|
|
||||||
c.JSON(200, ErrorResponse(err))
|
|
||||||
}
|
}
|
||||||
|
//if err := c.ShouldBindJSON(&service); err == nil {
|
||||||
|
_ = service.ArchiveAndDownload(ctx, c)
|
||||||
|
//c.JSON(200, res)
|
||||||
|
//} else {
|
||||||
|
// c.JSON(200, ErrorResponse(err))
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnonymousGetContent 匿名获取文件资源
|
// AnonymousGetContent 匿名获取文件资源
|
||||||
|
|
|
@ -102,7 +102,7 @@ func InitRouter() *gin.Engine {
|
||||||
// 取得文件外链
|
// 取得文件外链
|
||||||
file.GET("source/:id", controllers.GetSource)
|
file.GET("source/:id", controllers.GetSource)
|
||||||
// 测试用:压缩文件和目录并下載
|
// 测试用:压缩文件和目录并下載
|
||||||
file.POST("archive", controllers.ArchiveAndDownload)
|
file.GET("archive", controllers.ArchiveAndDownload)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 目录
|
// 目录
|
||||||
|
|
|
@ -2,8 +2,8 @@ package explorer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem"
|
"github.com/HFO4/cloudreve/pkg/filesystem"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/filesystem/fsctx"
|
||||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
@ -40,13 +40,17 @@ func (service *ItemService) ArchiveAndDownload(ctx context.Context, c *gin.Conte
|
||||||
return serializer.Err(serializer.CodeGroupNotAllowed, "当前用户组无法进行此操作", nil)
|
return serializer.Err(serializer.CodeGroupNotAllowed, "当前用户组无法进行此操作", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始压缩,获取压缩后的stream
|
//// 写HTTP头
|
||||||
rs, err := fs.Compress(ctx, service.Dirs, service.Items)
|
//c.Header("Content-Type", "application/zip")
|
||||||
if err != nil {
|
//c.Header("Content-Disposition", "attachment; filename=\"archive.zip\"")
|
||||||
return serializer.Err(serializer.CodeNotSet, "无法创建压缩文件", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(rs)
|
// 开始压缩,获取压缩后的stream
|
||||||
|
ctx = context.WithValue(ctx, fsctx.GinCtx, c)
|
||||||
|
|
||||||
|
err = fs.Compress(ctx, service.Dirs, service.Items, c.Writer)
|
||||||
|
if err != nil {
|
||||||
|
return serializer.Err(serializer.CodeGroupNotAllowed, "无法创建", nil)
|
||||||
|
}
|
||||||
|
|
||||||
return serializer.Response{
|
return serializer.Response{
|
||||||
Code: 0,
|
Code: 0,
|
||||||
|
|
Loading…
Reference in a new issue