2016-10-25 80 views
1

我很努力地處理Go中的嵌套zip文件(其中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其爲os.File應該滿足NewReader要求。

我的問題:有沒有辦法打開一個嵌套的zip文件,而無需先將內容寫入磁盤上的文件,或將整個內容讀入內存。

它看起來像所有需要的東西在zip.File中可用,但不會被導出。我希望我錯過了一些東西。

+1

我擔心最簡單的做法是將其複製到'bytes.Buffer'或磁盤中。嵌套的拉鍊有多大? – captncraig

+0

您可能會發現https://godoc.org/golang.org/x/tools/godoc/vfs/zipfs的api也更具有適應性。不確定。 – captncraig

+0

@captncraig這是一個小型掃描程序,所以我不知道我會遇到什麼zip文件。我不確定這種情況會有多普遍,我只是覺得能夠使用流來將所有東西放在一起。好的調用'bytes.Buffer',我想我可以在閱讀整個事情之前檢查文件大小,因爲我可以訪問它。 – freb

回答

0

如何從io.Reader是重新初始化,如果你決定往回走的io.ReaderAt:(此代碼主要是未經測試,但希望你的想法)

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並行調用,並在全讀不阻止,所以這甚至可能不會正常工作