新一周的工作内容,基本就是研究这个zip文件的解压与压缩了。如上一篇一样,官方文档解释的并不是很清楚。google百度出来的结果都是有问题的,要不就是文件压缩之后,压缩内容变0kb 要不就是文件写入之后解压出来不知道是个什么鬼了。我只用了这一种方式,其他的gzip和tar等有时间在研究。不过我想也都大同小异了。先上代码,然后再说说我在研究的时候遇到的问题吧。

文件压缩

/**
@files:需要压缩的文件
@compreFile:压缩之后的文件
*/
func Compress_zip(files []*os.File, compreFile *os.File) (err error) {
    zw := zip.NewWriter(compreFile)
    defer zw.Close()
    for _, file := range files {
        err := compress_zip(file, zw)
        if err != nil {
            return err
        }
        file.Close()
    }
    return nil
}

/**
功能:压缩文件
@file:压缩文件
@prefix:压缩文件内部的路径
@tw:写入压缩文件的流
*/
func compress_zip(file *os.File, zw *zip.Writer) error {
    info, err := file.Stat()
    if err != nil {
        logs.Error("压缩文件失败:", err.Error())
        return err
    }
    // 获取压缩头信息
    head, err := zip.FileInfoHeader(info)
    if err != nil {
        logs.Error("压缩文件失败:", err.Error())
        return err
    }
    // 指定文件压缩方式 默认为 Store 方式 该方式不压缩文件 只是转换为zip保存
    head.Method = zip.Deflate
    fw, err := zw.CreateHeader(head)
    if err != nil {
        logs.Error("压缩文件失败:", err.Error())
        return err
    }
    // 写入文件到压缩包中
    _, err = io.Copy(fw, file)
    file.Close()
    if err != nil {
        logs.Error("压缩文件失败:", err.Error())
        return err
    }
    return nil
}

压缩文件的时候有一个Header的概念

type FileHeader

type FileHeader struct {
    // Name是文件名,它必须是相对路径,不能以设备或斜杠开始,只接受'/'作为路径分隔符
    Name string
    CreatorVersion     uint16
    ReaderVersion      uint16
    Flags              uint16
    Method             uint16
    ModifiedTime       uint16 // MS-DOS时间
    ModifiedDate       uint16 // MS-DOS日期
    CRC32              uint32
    CompressedSize     uint32 // 已弃用;请使用CompressedSize64
    UncompressedSize   uint32 // 已弃用;请使用UncompressedSize64
    CompressedSize64   uint64
    UncompressedSize64 uint64
    Extra              []byte
    ExternalAttrs      uint32 // 其含义依赖于CreatorVersion
    Comment            string
}

以上就是官方文档给出的FileHeader的一些讲解,大概就是描述压缩文件中文件的一些信息的,比方说文件压缩前大小、压缩后大小这些、文件名这些,压缩文件就是创建出zip文件然后用zip.NewWriter()获得对文件的压缩写入流。之后通过压缩写入流,创建出压缩文件的Header 然后把文件写入到Header中。这样就能达到压缩文件的目的了。这之中有一个需要注意的是压缩方式的问题。

const (
    Store   uint16 = 0  // 仅存储文件
    Deflate uint16 = 8 ) // 压缩文件

预定义压缩算法。
这是archive/zip包中预定义的两种压缩方式。一个是仅把文件写入到zip中。不做压缩。一种是压缩文件然后写入到zip中。

head.Method = zip.Deflate

如上就是设置文件的压缩模式。默认的Store模式。就是只保存不压缩的模式。

解压文件

/**
@tarFile:压缩文件路径
@dest:解压文件夹
*/
func DeCompressByPath(tarFile, dest string) error {
    srcFile, err := os.Open(tarFile)
    if err != nil {
        return err
    }
    defer srcFile.Close()
    return DeCompress(srcFile, dest)
}

/**
@zipFile:压缩文件
@dest:解压之后文件保存路径
*/
func DeCompress(srcFile *os.File, dest string) error {
    zipFile, err := zip.OpenReader(srcFile.Name())
    if err != nil {
        logs.Error("Unzip File Error:", err.Error())
        return err
    }
    defer zipFile.Close()
    for _, innerFile := range zipFile.File {
        info := innerFile.FileInfo()
        if info.IsDir() {
            err = os.MkdirAll(innerFile.Name, os.ModePerm)
            if err != nil {
                logs.Error("Unzip File Error : " + err.Error())
                return err
            }
            continue
        }
        srcFile, err := innerFile.Open()
        if err != nil {
            logs.Error("Unzip File Error : " + err.Error())
            continue
        }
        defer srcFile.Close()
        newFile, err := os.Create(innerFile.Name)
        if err != nil {
            logs.Error("Unzip File Error : " + err.Error())
            continue
        }
        io.Copy(newFile, srcFile)
        newFile.Close()
    }
    return nil
}

这个没什么太大问题。只是解压文件出来创建文件夹保存