在不解压到磁盘的情况下读取tar文件的内容

15
我已经能够循环遍历tar文件中的文件,但我不知道如何将这些文件内容读取为字符串。我想知道如何将文件内容打印为字符串?
以下是我的代码:
package main

import (
    "archive/tar"
    "fmt"
    "io"
    "log"
    "os"
    "bytes"
    "compress/gzip"
)

func main() {
    file, err := os.Open("testtar.tar.gz")

    archive, err := gzip.NewReader(file)

    if err != nil {
        fmt.Println("There is a problem with os.Open")
    }
    tr := tar.NewReader(archive)

    for {
        hdr, err := tr.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("Contents of %s:\n", hdr.Name)
    }
}
3个回答

18

只需将tar.Reader用作要读取的每个文件的io.Reader即可。

tr := tar.NewReader(r)

// get the next file entry 
h, _ := tr.Next() 

如果需要将整个文件作为字符串:

// read the complete content of the file h.Name into the bs []byte
bs, _ := ioutil.ReadAll(tr)

// convert the []byte to a string
s := string(bs)

如果您需要逐行阅读,那么这会更好:

// create a Scanner for reading line by line
s := bufio.NewScanner(tr)

// line reading loop
for s.Scan() {

  // read the current last read line of text
  l := s.Text()

  // ...and do something with l

}

// you should check for error at this point
if s.Err() != nil {
  // handle it
}

1
你不能期望读者知道类型,处理内容是你的责任。 - Anfernee
4
一个文件(无论是在硬盘上还是在 tar 文件中)的内容只是一堆字节,没有更多的内容。请解释原始问题。 - Volker
1
@m.. 请停下手头的一切工作,阅读 https://golang.org/doc/effective_go.html。 - OneOfOne
@PabloLalloni 我正在尝试从打包在tar文件中的txt文件中获取字符串。 - m..
@PabloLalloni好的,简洁的答案。如果您想逐行读取文件数据,该怎么做? - m..
显示剩余4条评论

1
有时我看到人们使用 tar.gz 作为临时数据库,因此我发现将归档文件读入 fstest.MapFS 中非常有用:
package main

import (
   "archive/tar"
   "compress/gzip"
   "io"
   "os"
   "testing/fstest"
)

func tarGzMemory(source string) (fstest.MapFS, error) {
   file, err := os.Open(source)
   if err != nil { return nil, err }
   defer file.Close()
   gzRead, err := gzip.NewReader(file)
   if err != nil { return nil, err }
   tarRead := tar.NewReader(gzRead)
   files := make(fstest.MapFS)
   for {
      cur, err := tarRead.Next()
      if err == io.EOF { break } else if err != nil { return nil, err }
      if cur.Typeflag != tar.TypeReg { continue }
      data, err := io.ReadAll(tarRead)
      if err != nil { return nil, err }
      files[cur.Name] = &fstest.MapFile{Data: data}
   }
   return files, nil
}

例子:

package main

func main() {
   m, e := tarGzMemory("mingw64.db.tar.gz")
   if e != nil {
      panic(e)
   }
   data := m["mingw-w64-x86_64-gcc-10.2.0-10/desc"].Data
   print(string(data))
}

https://golang.org/pkg/testing/fstest


-1

在官方网站的帮助下,这就是我先前打算的内容。需要特别关注底部,因为在那里进行了从字节到字符串的转换。

package main

import (
    "archive/tar"
    "fmt"
    "io"
    "log"
    "os"
    "bytes"
    "compress/gzip"
)

func main() {

    file, err := os.Open("testtar.tar.gz")

    archive, err := gzip.NewReader(file)

    if err != nil {
        fmt.Println("There is a problem with os.Open")
    }
    tr := tar.NewReader(archive)

    for {
        hdr, err := tr.Next()
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatal(err)
        }

        fmt.Printf("Contents of %s:\n", hdr.Name)

        //Using a bytes buffer is an important part to print the values as a string

        bud := new(bytes.Buffer)
        bud.ReadFrom(tr)
        s := bud.String()
        fmt.Println(s)
        fmt.Println()
    }

}

1
请将以下与编程���关的内容从英语翻译成中文。仅返回已翻译的文本:请检查我的答案,以便更轻松地将整个内容读入字符串。 - Pablo Lalloni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接