dtsps00544 2017-11-10 05:10
浏览 115
已采纳

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

I want to copy the data from an http response to a file and a buffer.

However, I can't quite figure this out.

Initially I had this:

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
}

So what I want actually is something like

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

Only, I cant pass buf into TeeReader as it doesn't implement the writer interface. I'm sure there is a proper method but I can't find it as I fumble around looking for an efficient way to do this.

How do I do this without allocating buffer after buffer. I was trying to be efficient. i.e. It seems silly to write the file and read it back.

What I've tried but doesn't work as expected.

    // 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条回答 默认 最新

  • dqssst0144 2017-11-10 13:08
    关注

    Just to make the (other) answer clear and complete: it's not io.TeeReader()'s fault that you were not able to copy the complete body to file and have it as a bytes.Buffer, but it's entirely io.CopyBuffer()'s fault.

    io.Copy() is the knight and shining armor, the one who keeps on copying until the whole input is consumed:

    Copy copies from src to dst until either EOF is reached on src or an error occurs.

    So an equivalently good solution using io.TeeReader():

    buf := bytes.NewBuffer(make([]byte, 0, resp.ContentLength))
    _, err = io.Copy(f, io.TeeReader(resp.Body, buf))
    return buf.Bytes(), err
    

    Using bytes.NewBuffer() like this you can pre-allocate the necessary buffer and avoid reallocation and copying (which makes it faster). Of course you can use this with io.MultiWriter() too.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 想问一下树莓派接上显示屏后出现如图所示画面,是什么问题导致的
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)
  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号