使用 Go 的 archive/zip 创建具有 Unicode 文件名的 zip 存档


package main
import (
    "archive/zip"
    "fmt"
    "io"
    "os"
    "path/filepath"
    "strings"
)
func main() {
    var (
        Path = os.Args[1]
        Name = os.Args[2]
    )
    File, _ := os.Create(Name)
    PS := strings.Split(Path, "\")
    PathName := strings.Join(PS[:len(PS)-1], "\")
    os.Chdir(PathName)
    Path = PS[len(PS)-1]
    defer File.Close()
    Zip := zip.NewWriter(File)
    defer Zip.Close()
    walk := func(Path string, info os.FileInfo, err error) error {
        if err != nil {
            fmt.Println(err)
            return err
        }
        if info.IsDir() {
            return nil
        }
        Src, _ := os.Open(Path)
        defer Src.Close()
        fmt.Println(Path)
        FileName, _ := Zip.Create(Path)
        io.Copy(FileName, Src)
        Zip.Flush()
        return nil
    }
    if err := filepath.Walk(Path, walk); err != nil {
        fmt.Println(err)
    }
}

这个mydir路径:

-----root
    |---2015-05(dir)
         |---中文.go
    |---package(dir)
    |---你好.go

当我使用此代码目录时,中文将被乱七八糟。谁可以帮助我解决问题。

问题是,默认情况下,zip输入名称中只允许zip规范允许ASCII字符,更具体地说:(来源:附录D)

附录D.1 ZIP格式历史上仅支持原始IBM PC字符 编码集,通常称为IBM代码第437页。这限制了存储 文件名字符仅针对原始MS-DOS范围内的文件字符 并且没有正确支持其他字符编码中的文件名,或 语言。为了解决此限制,此规范将支持 以下更改。

后来添加了对Unicode名称的支持。可以用一个特殊的位标记为general purpose bit 11,也称为Language encoding flag (EFS)

第4.4.4.4节 - 通用位数标志 - 位11-语言编码标志(EFS)。如果设置了此位,则必须使用UTF-8编码此文件的文件名和注释字段。

附录D.2 如果通用位11尚未设置,则文件名和评论应符合 到原始的zip字符编码。如果设置了通用位11, 文件名和评论必须支持Unicode标准版本4.1.0或 使用UTF-8存储定义的字符编码表格更大 规格。Unicode标准由Unicode发布 财团(www.unicode.org)。UTF-8编码数据存储在zip文件中 预计不包括字节订单标记(BOM)。

general purpose bit flag是由GO出现并支持的:它是FileHeader结构的Flags字段。不幸的是,GO没有设置此位的方法,默认情况下它是0。

因此,添加对Unicode名称的支持的最简单方法就是将bit 11设置为一个。而不是

FileName, _ := Zip.Create(Path)

以:

开始您的ZIP条目
h := &zip.FileHeader{Name:Path, Method: zip.Deflate, Flags: 0x800}
FileName, _ := Zip.CreateHeader(h)

第一行创建一个FileHeader,其中为Flags字段设置了0x800bit 11)值,该字段告诉该文件名将使用UTF-8编码文件名(这是将string写入io.Writer时GO所做的。<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<)/p>

注意:

这样做,将保留UTF-8文件名,但并非所有ZIP读取器/提取器都支持它。例如,在Windows,Windows文件处理程序上,Windows Explorer不会将其解码为UTF-8,但是例如,更严肃的Zip处理程序(例如SecureZip)将看到UTF-8文件名并将其正确提取文件名(使用UTF-8解码)。

package main
import (
    "archive/zip"
    "fmt"
    "io"
    "os"
    "path/filepath"
    "strings"
)
func main() {
    var (
        Path = os.Args[1]
        Name = os.Args[2]
    )
    File, _ := os.Create(Name)
    PS := strings.Split(Path, "\")
    PathName := strings.Join(PS[:len(PS)-1], "\")
    os.Chdir(PathName)
    Path = PS[len(PS)-1]
    defer File.Close()
    Zip := zip.NewWriter(File)
    defer Zip.Close()
    walk := func(Path string, info os.FileInfo, err error) error {
        if err != nil {
            fmt.Println(err)
            return err
        }
        if info.IsDir() {
            return nil
        }
        Src, _ := os.Open(Path)
        defer Src.Close()
        //FileName, _ := Zip.Create(Path)
        h := &zip.FileHeader{Name: Path, Method: zip.Deflate, Flags: 0x800}
        FileName, _ := Zip.CreateHeader(h)
        io.Copy(FileName, Src)
        Zip.Flush()
        return nil
    }
    if err := filepath.Walk(Path, walk); err != nil {
        fmt.Println(err)
    }
}

最新更新