go io.copy函数在处理大型内容时存在一致的偏移一个错误。

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

Consistent off by one errors in go io.copy function for large content

问题

这个代码段可以正常工作:

_, err = io.Copy(out, resp.Body)
if err != nil {
    ErrLog.Fatal(err)
}

这个代码段在处理较大的响应(几兆字节)时会产生一致的偏移一个字节的错误(在下载内容的最后一个字节被省略,例如在 JSON 响应中省略了一个闭合的 ]):

if _, err := io.Copy(out, resp.Body); err != nil {
    ErrLog.Fatal(err)
}

根据官方 Golang 博客上的示例,这个语法应该是有效的。

编辑:更多细节和背景信息

这是我在第二个版本的代码(更紧凑的错误处理)中遇到的错误:

ERROR: 2015/08/05 08:09:31 pull.go:257: unexpected end of JSON input

以下是另一个函数中的代码:

err = json.Unmarshal(dat, &all_data)
if err != nil {
    return err
}

我通过查看每种情况下文件的前10个和后10个字符来发现了偏移一个字节的问题。以下是修改前后的对比:

# 修改前(存在错误)
START:  [{"tags":[              END:    ersion":1}
START:  [{"_create              END:    "tags":[]}

# 修改后
START:  [{"tags":[              END:    rsion":1}]
START:  [{"_create              END:    tags":[]}]

这些文件是 15-20 MB 的 JSON 字符串。

英文:

This one works consistently.

	_, err = io.Copy(out, resp.Body)
	if err != nil {
		ErrLog.Fatal(err)
	}

This one gives pretty consistent off by one errors (the last byte of the downloaded content is left off, in my case a closing ] in a json response) for large-ish responses (MBs).

	if _, err := io.Copy(out, resp.Body); err != nil {
		ErrLog.Fatal(err)
	}

From the examples on the official golang blog, it looks like this should be valid syntax.

Edit: Some more details and context

This is the error I get with the 2nd version of the code (more compact error handling)

ERROR: 2015/08/05 08:09:31 pull.go:257: unexpected end of JSON input

From this code in another function

err = json.Unmarshal(dat, &all_data)
if err != nil {
	return err
}

I found the off by one issue by looking at the first 10 and last 10 characters of the file in each case. Here are the before and afters:

# Before (with error)
START:  [{"tags":[              END:    ersion":1}
START:  [{"_create              END:    "tags":[]}

# After
START:  [{"tags":[              END:    rsion":1}]
START:  [{"_create              END:    tags":[]}]

The files are 15-20 Mb json strings.

答案1

得分: 0

问题至少部分是由于竞态条件引起的。

在退出函数之前,我没有对文件out调用.Close()。添加了这个之后,问题就没有再出现了。

为什么仅仅是最后一个字节有时会丢失,对我来说还是个谜。

英文:

It turned out the issue was at least partially the result of a race condition.

I was not calling .Close() on the file out before exiting the function. After adding that I have not been any more issues.

Why exactly this was causing just the last byte of the file to get dropped sometimes is a mystery to me.

huangapple
  • 本文由 发表于 2015年8月5日 20:18:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/31832335.html
匿名

发表评论

匿名网友

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

确定