读取 tar 文件的内容而不解压到磁盘上。

huangapple go评论75阅读模式
英文:

Read contents of tar file without unzipping to disk

问题

我已经能够循环遍历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)
    }
}

请注意,这只是打印了文件的名称,如果你想要打印文件的内容作为字符串,你需要在循环中添加读取文件内容的代码。

英文:

I have been able to loop through the files in a tar file, but I am stuck on how to read the contents of those files as string. I would like to know how to print the contents of the files as a string?

This is my code below

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)
    }
}

答案1

得分: 16

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

tr := tar.NewReader(r)

// 获取下一个文件条目
h, _ := tr.Next()

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

// 将文件h.Name的完整内容读取到bs []byte中
bs, _ := ioutil.ReadAll(tr)

// 将[]byte转换为字符串
s := string(bs)

如果您需要逐行读取则可以使用以下方法

// 创建用于逐行读取的Scanner
s := bufio.NewScanner(tr)

// 逐行读取循环
for s.Scan() {

  // 读取当前最后一行文本
  l := s.Text()

  // ...并对l进行处理

}

// 此时应检查错误
if s.Err() != nil {
  // 处理错误
}
英文:

Just use the tar.Reader as an io.Reader for each file you want to read.

tr := tar.NewReader(r)

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

If you need the whole file as a string:

// 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)

If you need to read line by line, then this would be better:

// 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
}

答案2

得分: 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

英文:

Sometimes I have seen people use tar.gz as a makeshift database, so I found it
useful to read the archive into a 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
}

Example:

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

答案3

得分: -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()
    }

}

帮助完成翻译后,请将翻译结果返回给我。

英文:

With some help from the official site this is what I had intended previously. Special focus should be turned to the bottom where the conversion from bytes to string is made.

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()
    }

}

huangapple
  • 本文由 发表于 2017年3月3日 03:22:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/42564146.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定