有没有大神 知道,go 处理解压, rar格式压缩包的

mannysys · 2018-11-16 17:46:38 · 1662 次点击

3楼 @mannysys

package main

import (
    "fmt"
    "io"
    "os"
    "path/filepath"
    "runtime"

    "github.com/mholt/archiver"
    "github.com/nwaples/rardecode"
    "github.com/schollz/progressbar"
)

func main() {
    r := archiver.NewRar()

    count := 0
    err := r.Walk("mytest.rar", func(f archiver.File) error {
        if !f.IsDir() {
            count += 1
        }
        return nil
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("File count: ", count)

    bar := progressbar.New(count)
    destination := "./"

    err = r.Walk("mytest.rar", func(f archiver.File) error {
        rh, ok := f.Header.(*rardecode.FileHeader)
        if !ok {
            return fmt.Errorf("expected header")
        }

        to := destination + rh.Name
        if !f.IsDir() && !r.OverwriteExisting && fileExists(to) {
            return fmt.Errorf("file already exists: %s", to)
        }

        // if files come before their containing folders, then we must
        // create their folders before writing the file
        err := mkdir(filepath.Dir(to))
        if err != nil {
            return fmt.Errorf("making parent directories: %v", err)
        }

        if f.IsDir() {
            return nil
        }
        bar.Add(1)
        return writeNewFile(to, f.ReadCloser, rh.Mode())
    })
    if err != nil {
        panic(err)
    }
}

func writeNewFile(fpath string, in io.Reader, fm os.FileMode) error {
    err := os.MkdirAll(filepath.Dir(fpath), 0755)
    if err != nil {
        return fmt.Errorf("%s: making directory for file: %v", fpath, err)
    }

    out, err := os.Create(fpath)
    if err != nil {
        return fmt.Errorf("%s: creating new file: %v", fpath, err)
    }
    defer out.Close()

    err = out.Chmod(fm)
    if err != nil && runtime.GOOS != "windows" {
        return fmt.Errorf("%s: changing file mode: %v", fpath, err)
    }

    _, err = io.Copy(out, in)
    if err != nil {
        return fmt.Errorf("%s: writing file: %v", fpath, err)
    }
    return nil
}

func fileExists(name string) bool {
    _, err := os.Stat(name)
    return !os.IsNotExist(err)
}

func mkdir(dirPath string) error {
    err := os.MkdirAll(dirPath, 0755)
    if err != nil {
        return fmt.Errorf("%s: making directory: %v", dirPath, err)
    }
    return nil
}

这个库只提供了顺序遍历文件的方式,不完整遍历一遍就不知道到底有多少个文件.

而第一次的遍历获取文件总数的时候会消耗很长时间,暂时没想到什么好办法,

可能需要fork下来,自己改源码

#5
更多评论

一个简单的示例,不过这个库还不支持压缩

package main

import (
    "fmt"
    "io/ioutil"

    "github.com/mholt/archiver"
    "github.com/nwaples/rardecode"
)

func main() {
    r := archiver.NewRar()

    err := r.Walk("mytest.rar", func(f archiver.File) error {
        rh, ok := f.Header.(*rardecode.FileHeader)
        if !ok {
            return fmt.Errorf("expected header")
        }
        fmt.Println("FileName:", rh.Name)

        content, err := ioutil.ReadAll(f)
        if err != nil {
            return err
        }
        fmt.Println("FileContent:", string(content))

        return nil
    })
    if err != nil {
        panic(err)
    }

    err = r.Unarchive("mytest.rar", "mytest")
    if err != nil {
        panic(err)
    }
}
#2