【问题标题】:How to read from either gzip or plain text reader in golang?如何从 golang 中的 gzip 或纯文本阅读器读取?
【发布时间】:2015-02-03 22:28:39
【问题描述】:

我正在用 golang 编写一个小型 webapp,它涉及解析用户上传的文件。我想自动检测文件是否被压缩并适当地创建阅读器/扫描仪。一个转折是我无法将整个文件读入内存,我只能单独对流进行操作。这是我得到的:

func scannerFromFile(reader io.Reader) (*bufio.Scanner, error) {

var scanner *bufio.Scanner
//create a bufio.Reader so we can 'peek' at the first few bytes
bReader := bufio.NewReader(reader)

testBytes, err := bReader.Peek(64) //read a few bytes without consuming
if err != nil {
    return nil, err
}
//Detect if the content is gzipped
contentType := http.DetectContentType(testBytes)

//If we detect gzip, then make a gzip reader, then wrap it in a scanner
if strings.Contains(contentType, "x-gzip") {
    gzipReader, err := gzip.NewReader(bReader)
    if (err != nil) {
        return nil, err
    }

    scanner = bufio.NewScanner(gzipReader)

} else {
    //Not gzipped, just make a scanner based on the reader
    scanner = bufio.NewScanner(bReader)
}

return scanner, nil
}

这适用于纯文本,但对于 gzip 压缩的数据,它会错误地膨胀,并且在几 kb 之后,我不可避免地会得到乱码。有没有更简单的方法?任何想法为什么在几千行之后它会错误地解压缩?

【问题讨论】:

  • 让我怀疑这段代码之外的内容是否有问题——来自 gzip 阅读器的乱码文本绝对是我没想到的。 (编辑:哎呀,“不要”很重要。:))
  • 代码对我来说看起来是正确的。我推荐contentType == "application/x-gzip" 而不是strings.Contains。
  • 如果压缩流本身已损坏,我希望您会收到 CRC 错误;可能是压缩前或解压后的东西——无论如何,我担心这里可能没有足够的信息来解决问题。

标签: go gzip


【解决方案1】:

您可以通过检查前 2 个字节是否等于 0x1f8b 来检测文件是否被 gzip(我发现了该信息 here)。

在 cmets 中有人提到你应该分别检查这些字节,所以第一个是 0x1f,第二个是 0x8b

testBytes, err := bReader.Peek(2) //read 2 bytes
....
if testBytes[0] == 31 && testBytes[1] == 139 {
    //gzip
}else{
   ...
}

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    谢谢大家 - 事实证明 twotwotwo 和thundercat 是正确的,并且流在与我发布的代码无关的位置被破坏。奇怪的是,这似乎与在从请求流中读取的同时写入 http 响应有关。我仍在调查它,但似乎最初的问题被误导了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多