Golang中Yeka/zip库不支持zip v6.3压缩算法的问题

Golang中Yeka/zip库不支持zip v6.3压缩算法的问题 尝试解压一个受密码保护的 v6.3 版本 zip 文件时,遇到了 不支持的压缩算法 错误。 目前我正在使用 GitHub - yeka/zip: Fork of Go’s archive/zip to add reading/writing of password protected zip files.。该库适用于 v5.1 版本的 zip 文件。 请问有人能提供一些建议或指导吗?

v6.3 版本 zip 文件的详细信息如下:

  • 密码加密方法:AES256
  • 压缩算法:PPMd

v6.3 版本的 zip 文件可以使用 7z 创建,命令如下:

7z a -tzip -ppassword -mem=AES256 target_zip.zip file.pdf -m0=PPMd

更多关于Golang中Yeka/zip库不支持zip v6.3压缩算法的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

嗯,PPMd 实际上是 yeka/zip 支持的压缩算法吗?

这些代码行暗示支持的压缩方法是 Store 和 Deflate?

我知道你提到你在另一个独立的例子中让它运行起来了,我想知道那个实验的条件是否相同?

更多关于Golang中Yeka/zip库不支持zip v6.3压缩算法的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你说得完全正确。虽然我确实提供了一些关于 yeka/zip 及其功能的信息,但关于它支持 PPMd 压缩的说法似乎是我搞错了。根据官方文档和你链接的讨论,yeka/zip 目前不支持 PPMd 压缩

你提到的代码行正确地说明了支持的压缩方法是 Store 和 Deflate。

对于提供的不准确信息,我表示歉意。我仍在开发中,正在学习如何准确地处理信息。感谢你指出我的错误并帮助我学习!

根据你的描述,问题确实出在Yeka/zip库不支持PPMd压缩算法。这个库虽然扩展了标准库的密码保护功能,但压缩算法支持有限。

以下是具体的技术分析和解决方案:

问题分析

Yeka/zip库基于Go标准库的archive/zip,主要增加了AES加密支持,但压缩算法只支持:

  • Store(不压缩)
  • Deflate(标准压缩)
  • 部分BZIP2支持

不支持PPMd(Prediction by Partial Matching)算法,这是v6.3 zip文件使用的压缩方法。

解决方案

方案1:使用外部工具(推荐)

最可靠的方法是使用系统命令调用7z或unzip:

package main

import (
    "fmt"
    "os/exec"
    "path/filepath"
)

func extractZipWith7z(zipPath, outputDir, password string) error {
    cmd := exec.Command("7z", "x", zipPath, 
        fmt.Sprintf("-p%s", password),
        fmt.Sprintf("-o%s", outputDir),
        "-y") // 自动确认覆盖
    
    output, err := cmd.CombinedOutput()
    if err != nil {
        return fmt.Errorf("解压失败: %v\n输出: %s", err, output)
    }
    
    return nil
}

func main() {
    err := extractZipWith7z("target_zip.zip", "./output", "password")
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    }
}

方案2:使用支持更多算法的Go库

目前没有完美的纯Go解决方案,但可以尝试以下组合:

package main

import (
    "archive/zip"
    "fmt"
    "io"
    "os"
    
    "github.com/yeka/zip"
    "github.com/klauspost/compress/zip" // 注意:需要检查PPMd支持
)

// 混合方法:先用yeka/zip处理加密,再用其他库解压
func extractAESProtectedZip(zipPath, password string) error {
    // 注意:这只是一个概念示例,实际需要更多处理
    r, err := zip.OpenReader(zipPath)
    if err != nil {
        return err
    }
    defer r.Close()
    
    for _, f := range r.File {
        if f.IsEncrypted() {
            f.SetPassword(password)
        }
        
        rc, err := f.Open()
        if err != nil {
            return err
        }
        
        // 这里需要处理PPMd解压
        // 标准库和yeka/zip都不支持PPMd
    }
    
    return nil
}

方案3:修改创建参数

如果可能,创建zip时使用兼容的压缩算法:

// 创建兼容的zip文件(使用7z命令行)
func createCompatibleZip(sourceFile, zipPath, password string) error {
    cmd := exec.Command("7z", "a", 
        "-tzip",
        fmt.Sprintf("-p%s", password),
        "-mem=AES256",
        zipPath,
        sourceFile,
        "-m0=Deflate") // 使用Deflate而不是PPMd
    
    return cmd.Run()
}

当前限制

  1. 纯Go解决方案有限:目前没有成熟的Go库完全支持所有zip压缩算法
  2. PPMd支持:PPMd是专利算法,开源实现较少
  3. 性能考虑:PPMd解压需要更多内存和CPU资源

临时解决方案代码

如果必须使用Go处理,可以考虑先转换为兼容格式:

func convertZipToCompatibleFormat(inputZip, outputZip, password string) error {
    // 创建临时目录
    tmpDir, err := os.MkdirTemp("", "zipconvert")
    if err != nil {
        return err
    }
    defer os.RemoveAll(tmpDir)
    
    // 用7z解压
    extractCmd := exec.Command("7z", "x", inputZip,
        fmt.Sprintf("-p%s", password),
        fmt.Sprintf("-o%s", tmpDir),
        "-y")
    
    if err := extractCmd.Run(); err != nil {
        return fmt.Errorf("解压失败: %v", err)
    }
    
    // 用Go重新压缩(使用Deflate)
    files, err := os.ReadDir(tmpDir)
    if err != nil {
        return err
    }
    
    // 使用yeka/zip创建新的加密zip
    outFile, err := os.Create(outputZip)
    if err != nil {
        return err
    }
    defer outFile.Close()
    
    zipWriter := zip.NewWriter(outFile)
    defer zipWriter.Close()
    
    for _, file := range files {
        if !file.IsDir() {
            filePath := filepath.Join(tmpDir, file.Name())
            addFileToZip(zipWriter, filePath, file.Name(), password)
        }
    }
    
    return nil
}

func addFileToZip(zipWriter *zip.Writer, filePath, zipPath, password string) error {
    fileToZip, err := os.Open(filePath)
    if err != nil {
        return err
    }
    defer fileToZip.Close()
    
    info, err := fileToZip.Stat()
    if err != nil {
        return err
    }
    
    header, err := zip.FileInfoHeader(info)
    if err != nil {
        return err
    }
    
    header.Name = zipPath
    header.Method = zip.Deflate
    
    writer, err := zipWriter.Encrypt(header.Name, password, zip.AES256Encryption)
    if err != nil {
        return err
    }
    
    _, err = io.Copy(writer, fileToZip)
    return err
}

建议优先使用方案1(外部工具调用),这是目前最稳定可靠的解决方案。

回到顶部