首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用存档/ zip处理嵌套zip文件

使用存档/ zip处理嵌套zip文件
EN

Stack Overflow用户
提问于 2016-10-25 16:46:27
回答 2查看 1.4K关注 0票数 2

我很难处理Go中的嵌套zip文件(其中zip文件包含另一个zip文件)。我正在尝试恢复一个zip文件并列出它包含的所有文件。

zip /zip为您提供了处理zip文件的两种方法:

  • zip.NewReader
  • zip.OpenReader

OpenReader在磁盘上打开一个文件。NewReader接受io.ReaderAt和文件大小。当您使用这两个文件中的任何一个迭代压缩文件时,您将为zip中的每个文件提取一个zip.File。要获取文件f的文件内容,您可以调用f.Open,这将给您提供一个zip.ReadCloser。要打开嵌套的zip文件,我需要使用NewReader,但是zip.Filezip.ReadCloser不能满足io.ReaderAt接口。

zip.File有一个专用字段zipr,它是一个io.ReaderAtzip.ReadCloser有一个私有字段f,它是一个满足NewReader需求的os.File

我的问题是:是否有任何方法可以打开嵌套的zip文件,而不首先将内容写入磁盘上的文件,或者将全部内容读入内存。

看起来,所需的一切都可以在zip.File中使用,但不能导出。我希望我错过了什么。

EN

回答 2

Stack Overflow用户

发布于 2016-10-27 02:27:57

如果您决定向后返回,那么从一个重新初始化的io.ReaderAt中得到一个io.Reader怎么样?(这段代码基本上没有经过测试,但希望您能理解)

代码语言:javascript
复制
package main

import (
    "io"
    "io/ioutil"
    "os"
    "strings"
)

type inefficientReaderAt struct {
    rdr    io.ReadCloser
    cur    int64
    initer func() (io.ReadCloser, error)
}

func newInefficentReaderAt(initer func() (io.ReadCloser, error)) *inefficientReaderAt {
    return &inefficientReaderAt{
        initer: initer,
    }
}

func (r *inefficientReaderAt) Read(p []byte) (n int, err error) {
    n, err = r.rdr.Read(p)
    r.cur += int64(n)
    return n, err
}

func (r *inefficientReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
    // reset on rewind
    if off < r.cur || r.rdr == nil {
        r.cur = 0
        r.rdr, err = r.initer()
        if err != nil {
            return 0, err
        }
    }

    if off > r.cur {
        sz, err := io.CopyN(ioutil.Discard, r.rdr, off-r.cur)
        n = int(sz)
        if err != nil {
            return n, err
        }
    }

    return r.Read(p)
}

func main() {
    r := newInefficentReaderAt(func() (io.ReadCloser, error) {
        return ioutil.NopCloser(strings.NewReader("ABCDEFG")), nil
    })

    io.Copy(os.Stdout, io.NewSectionReader(r, 0, 3))
    io.Copy(os.Stdout, io.NewSectionReader(r, 1, 3))
}

如果你大部分时间都向前移动,这可能是可行的。尤其是如果你使用缓冲的读取器。

  • 我应该指出,这违反了io.ReaderAt保证:https://godoc.org/io#ReaderFrom,即它不允许对ReadAt的并行调用,也不阻止完全读取,因此这甚至可能无法正常工作。
票数 2
EN

Stack Overflow用户

发布于 2019-05-12 12:46:22

我遇到了同样的需要,想出了以下方法,不确定它是否对你有帮助:

代码语言:javascript
复制
// NewZipFromReader ...
func NewZipFromReader(file io.ReadCloser, size int64) (*zip.Reader, error) {
    in := file.(io.Reader)

    if _, ok := in.(io.ReaderAt); ok != true {
        buffer, err := ioutil.ReadAll(in)

        if err != nil {
            return nil, err
        }

        in = bytes.NewReader(buffer)
        size = int64(len(buffer))
    }

    reader, err := zip.NewReader(in.(io.ReaderAt), size)

    if err != nil {
        return nil, err
    }

    return reader, nil
}

因此,如果file不实现io.ReaderAt,则会将整个内容读入缓冲区。

处理ZIP炸弹可能不安全,对于大于RAM的文件,OOM也会失败。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40245442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档