如何获取压缩文件夹的大小
How to get the size of zipped folder
用例是:
我想压缩一个文件夹,其中可能包含 n 个不同大小的文件。我想添加限制,如果 zip 大小 > x (MB|GB) 则不创建 zip 并抛出错误。在迭代文件夹后创建 zip 后,我试图获取 zip 文件的大小,但无法这样做。在这里请求帮助。我正在使用 io.writer 创建 zip 文件而不是缓冲区。示例代码是
注意: 我可以使用“buf := new(bytes.Buffer)”来计算大小,但我想使用 io.writer 来计算如下所示
filepath - 文件夹路径
downloadLimit - 我想为下载的 zip 文件设置的限制。像 zip 文件大小不应超过 100 MB
func GetZipFileSize(filepath string, downloadLimit int, w io.Writer) error {
zipWriter := zip.NewWriter(w)
// List files
var files []FileAndPath
var err error
// We have function to fetch files in variable "files" which is used below
// ZIP files
for _, file := range files {
// Determine filename in ZIP
zipFilename := file.Path
filename := fp.Join(SOME_PATH, file.Path)
// Create ZIP entry
fileToZip, err := os.Open(filename)
if err != nil {
return SOME_ERROR
}
info, err := fileToZip.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = zipFilename
header.Method = zip.Deflate
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
// Set content for ZIP entry
if _, err = io.Copy(writer, fileToZip); err != nil {
return err
}
if err = fileToZip.Close(); err != nil {
// Nothing
}
}
// Wrap-up
if err := zipWriter.Close(); err != nil {
return err
}
return nil
}
以上函数创建 zip 文件,但我希望它在达到限制后立即停止创建并退出,或者至少获取创建的 zip 文件的大小
这是解决此问题的建议。代码中的解释。
我认为没有(简单的)方法可以 calculate/estimate 在不执行实际压缩的情况下确定未来 zip 文件的大小。
代码的第 1 行假定您已经有了要压缩的文件的某种字节表示形式。
func main() {
// Create a buffer to write our archive to (in memory)
buf := new(bytes.Buffer)
// Create a new zip archive writer, that writes to our in memory buffer
archiveWriter := zip.NewWriter(buf)
// ensure to close your zip writer later
defer archiveWriter.Close()
// you probably want to do this in a loop and repeat for each file you want add to the zip archive
// this is the content of a file you want to zip / instead read it from disk with ioutil.ReadFile() or some other approach
dummyBytes := []byte("ThisCouldBeTheContentOfYourSourceFile")
fileWriter, _ := archiveWriter.Create("fileNameOfSourceFileInZip")
_, _ = fileWriter.Write(dummyBytes)
// validate the in memory representation of the zip file does not exceed your limit
if buf.Len() > 1000 {
// todo raise error
return
}
// write the zip file to the disk, you could ofc also use io.writer
_ = ioutil.WriteFile("TargetZipFile.zip", buf.Bytes(), 0644)
}
请注意,我没有实施任何错误处理 - 您可能需要添加它。
标准 API 不提供 io.Writer
implementaion to do that, afaik. It exists a LimitReader
但它对您的情况没有多大用处,并且会导致我们编写相当复杂的代码。
相反,您可以编写自己的 io.Writer
包装器实现,以确保如果写入其中的总字节数超过或即将超过某个长度,return 会出错。
package main
import (
"errors"
"fmt"
"io"
"os"
"strings"
)
func main() {
bigBuf := strings.NewReader(strings.Repeat("borng string", 10000))
dst := &LimitWriter{Writer: os.Stdout, N: 20}
n, err := io.Copy(dst, bigBuf)
fmt.Println("n=", n)
fmt.Println("err=", err)
}
var ErrWriteOverflow = errors.New("write overflow, data is too large")
type LimitWriter struct {
io.Writer
N int64
written int64
}
func (l *LimitWriter) Write(p []byte) (n int, err error) {
if l.written+int64(len(p)) >= l.N {
return 0, ErrWriteOverflow
}
n, err = l.Writer.Write(p)
l.written += int64(n)
return
}
用例是: 我想压缩一个文件夹,其中可能包含 n 个不同大小的文件。我想添加限制,如果 zip 大小 > x (MB|GB) 则不创建 zip 并抛出错误。在迭代文件夹后创建 zip 后,我试图获取 zip 文件的大小,但无法这样做。在这里请求帮助。我正在使用 io.writer 创建 zip 文件而不是缓冲区。示例代码是
注意: 我可以使用“buf := new(bytes.Buffer)”来计算大小,但我想使用 io.writer 来计算如下所示
filepath - 文件夹路径 downloadLimit - 我想为下载的 zip 文件设置的限制。像 zip 文件大小不应超过 100 MB
func GetZipFileSize(filepath string, downloadLimit int, w io.Writer) error {
zipWriter := zip.NewWriter(w)
// List files
var files []FileAndPath
var err error
// We have function to fetch files in variable "files" which is used below
// ZIP files
for _, file := range files {
// Determine filename in ZIP
zipFilename := file.Path
filename := fp.Join(SOME_PATH, file.Path)
// Create ZIP entry
fileToZip, err := os.Open(filename)
if err != nil {
return SOME_ERROR
}
info, err := fileToZip.Stat()
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
if err != nil {
return err
}
header.Name = zipFilename
header.Method = zip.Deflate
writer, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
// Set content for ZIP entry
if _, err = io.Copy(writer, fileToZip); err != nil {
return err
}
if err = fileToZip.Close(); err != nil {
// Nothing
}
}
// Wrap-up
if err := zipWriter.Close(); err != nil {
return err
}
return nil
}
以上函数创建 zip 文件,但我希望它在达到限制后立即停止创建并退出,或者至少获取创建的 zip 文件的大小
这是解决此问题的建议。代码中的解释。 我认为没有(简单的)方法可以 calculate/estimate 在不执行实际压缩的情况下确定未来 zip 文件的大小。
代码的第 1 行假定您已经有了要压缩的文件的某种字节表示形式。
func main() {
// Create a buffer to write our archive to (in memory)
buf := new(bytes.Buffer)
// Create a new zip archive writer, that writes to our in memory buffer
archiveWriter := zip.NewWriter(buf)
// ensure to close your zip writer later
defer archiveWriter.Close()
// you probably want to do this in a loop and repeat for each file you want add to the zip archive
// this is the content of a file you want to zip / instead read it from disk with ioutil.ReadFile() or some other approach
dummyBytes := []byte("ThisCouldBeTheContentOfYourSourceFile")
fileWriter, _ := archiveWriter.Create("fileNameOfSourceFileInZip")
_, _ = fileWriter.Write(dummyBytes)
// validate the in memory representation of the zip file does not exceed your limit
if buf.Len() > 1000 {
// todo raise error
return
}
// write the zip file to the disk, you could ofc also use io.writer
_ = ioutil.WriteFile("TargetZipFile.zip", buf.Bytes(), 0644)
}
请注意,我没有实施任何错误处理 - 您可能需要添加它。
标准 API 不提供 io.Writer
implementaion to do that, afaik. It exists a LimitReader
但它对您的情况没有多大用处,并且会导致我们编写相当复杂的代码。
相反,您可以编写自己的 io.Writer
包装器实现,以确保如果写入其中的总字节数超过或即将超过某个长度,return 会出错。
package main
import (
"errors"
"fmt"
"io"
"os"
"strings"
)
func main() {
bigBuf := strings.NewReader(strings.Repeat("borng string", 10000))
dst := &LimitWriter{Writer: os.Stdout, N: 20}
n, err := io.Copy(dst, bigBuf)
fmt.Println("n=", n)
fmt.Println("err=", err)
}
var ErrWriteOverflow = errors.New("write overflow, data is too large")
type LimitWriter struct {
io.Writer
N int64
written int64
}
func (l *LimitWriter) Write(p []byte) (n int, err error) {
if l.written+int64(len(p)) >= l.N {
return 0, ErrWriteOverflow
}
n, err = l.Writer.Write(p)
l.written += int64(n)
return
}