如何将http内容流式传输到文件和缓冲区?

时间:2017-11-10 05:10:36

标签: go

我想将数据从http响应复制到文件和缓冲区。

但是,我无法理解这一点。

最初我有这个:

func DownloadS3(hash string, cluster Cluster, tok *oauth.Token, offset, length int64, f *os.File) ([]byte, error) {

    // ... other code not shown ...

    resp, err = DoHTTPRequest("GET", s3tok.URL, nil, reqhdr, defaultClientTimeout)
    if err != nil {
        fmt.Println("Error downloading from cluster:", err)
        return nil, err
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 && resp.StatusCode != 206 {
        return nil, err
    }

    // Create buffer to return actual content
    buf := make([]byte, resp.ContentLength)

    // This actually does copy the whole downloaded data to the file as
    // expected.  However, I didn't expect io.CopyBuffer to not use the entire
    // buffer.  It ends up returning a portion of the file.
    _, err = io.CopyBuffer(f, resp.Body, buf)

    return buf, err
}

所以我想要的实际上就像是

_, err = io.CopyBuffer(f, io.TeeReader(resp.Body, buf), nil)

只是,我不能将buf传递给TeeReader,因为它没有实现编写器接口。我确定有一个合适的方法,但我无法找到它,因为我摸索 在寻找一种有效的方法来做到这一点。

如何在不在缓冲区之后分配缓冲区的情况下执行此操作。我试图提高效率。即写文件并将其读回来似乎很愚蠢。

我尝试过的但是没有按预期工作。

    // Create buffer to return actual content
    buf := make([]byte, resp.ContentLength)
    _, err = io.CopyBuffer(f, io.TeeReader(resp.Body,bytes.NewBuffer(buf)), nil)
    return buf, nil

2 个答案:

答案 0 :(得分:2)

在数据写入文件时,使用io.MultiWriterbytes.Buffer获取数据副本:

var buf bytes.Buffer
_, err := io.Copy(io.MultiWriter(f, &buf), resp.Body)
return buf.Bytes(), err

无法保证io.CopyBuffer会写入整个缓冲区。当在io.Reader.Read的单个调用中读取整个响应主体时,当前实现将仅使用整个缓冲区。在您的示例中,整个响应主体需要多次读取才能进行啜食。

答案 1 :(得分:1)

只是为了让(其他)答案清晰完整:io.TeeReader()没有错误,你无法将整个正文复制到文件并将其作为bytes.Buffer,但它是完全io.CopyBuffer()的错。

io.Copy()是骑士和闪亮的盔甲,持续复制直到整个输入被消耗:

  

将副本从src复制到dst,直到在src上达到EOF或发生错误。

使用io.TeeReader()

这是一个相当不错的解决方案
buf := bytes.NewBuffer(make([]byte, 0, resp.ContentLength))
_, err = io.Copy(f, io.TeeReader(resp.Body, buf))
return buf.Bytes(), err

像这样使用bytes.NewBuffer(),你可以预先分配必要的缓冲区,避免重新分配和复制(这会使它更快)。当然,您也可以将其与io.MultiWriter()一起使用。