Arrays 跟踪和显示下载文件摘要(百分比)-Go lang

Arrays 跟踪和显示下载文件摘要(百分比)-Go lang,arrays,io,go,byte,Arrays,Io,Go,Byte,我正在做一个通过传递的url参数下载文件的过程。下载正在正确完成,但我不能做的是打印下载完成百分比的摘要。(每秒钟) 我做了一个模拟的总结,但它没有下载任何东西,它只是为了显示我想要它 我试图将io.copy放在我的源代码中,以便在复制过程中对其进行更改和打印,但失败了 有人能帮我吗? 谢谢 主程序包 进口( “fmt” “io” “net/http” “操作系统” “字符串” //“时间” ) func downloadFromUrl(url字符串){ 标记:=strings.Split(ur

我正在做一个通过传递的url参数下载文件的过程。下载正在正确完成,但我不能做的是打印下载完成百分比的摘要。(每秒钟)

我做了一个模拟的总结,但它没有下载任何东西,它只是为了显示我想要它

我试图将io.copy放在我的源代码中,以便在复制过程中对其进行更改和打印,但失败了

有人能帮我吗? 谢谢

主程序包
进口(
“fmt”
“io”
“net/http”
“操作系统”
“字符串”
//“时间”
)
func downloadFromUrl(url字符串){
标记:=strings.Split(url,“/”)
文件名:=令牌[len(令牌)-1]
Println(“下载”,url,“至”,文件名)
//创建文件
输出,错误:=os.Create(文件名)
如果错误!=零{
Println(“创建时出错”,文件名“-”,错误)
返回
}
fmt.Println(“创建”,文件名)
延迟输出。关闭()
//获取url
响应,错误:=http.Get(url)
如果错误!=零{
fmt.Println(“下载时出错”,url,“-”,err)
返回
}           
延迟响应。Body.Close()
//拷贝和字节
n、 err:=io.Copy(输出,响应,正文)
如果错误!=零{
fmt.Println(“下载时出错”,url,“-”,err)
返回
}
//跟踪进度
对于i:=1;float64(i)
我用
io.Reader
包装器在我的

// PassThru wraps an existing io.Reader.
//
// It simply forwards the Read() call, while displaying
// the results from individual calls to it.
type PassThru struct {
    io.Reader
    total    int64 // Total # of bytes transferred
    length   int64 // Expected length
    progress float64
}
在该包装器上定义一个
Read()
方法(使其成为
io.Reader

您可以使用该
io.Reader
读取(http请求的结果):

调用
ReadAll()
将触发实际下载,而
PassThru.Read()
将根据预期长度(
response.ContentLength
)打印下载的百分比


灵感:

  • 这是Copy()函数的一个例子
  • “”

您似乎假设如果
err==nil
那么
n==0
。那不一定是真的Read最多可将len(p)字节读入p。它返回读取的字节数(0@peterSO我不知道:在上面的代码中,如果
err==nil
,你在哪里看到
func(pt*PassThru)读取(p[]byte)(int,error)
你有
if err==nil{pt.total+=int64(n)}
。如果
err!=nil
,您不应该将
n
添加到
pt.total
中,您应该。CORRECTION s/err==nil/err!=nil/:您似乎假设如果
err!=nil
那么
n==0
。这不一定是真的。包io类型读取器:Read最多读取到p中的len(p)字节。它返回读取的字节数(0@peterSO我最终猜到了这一点(这就是我最初没有关注您的原因)。相关文档是:“调用方在考虑错误
err
之前,应该始终处理返回的
n>0
字节。这样做可以正确地处理读取某些字节后发生的I/O错误以及两种允许的EOF行为。”
// PassThru wraps an existing io.Reader.
//
// It simply forwards the Read() call, while displaying
// the results from individual calls to it.
type PassThru struct {
    io.Reader
    total    int64 // Total # of bytes transferred
    length   int64 // Expected length
    progress float64
}
// Read 'overrides' the underlying io.Reader's Read method.
// This is the one that will be called by io.Copy(). We simply
// use it to keep track of byte counts and then forward the call.
func (pt *PassThru) Read(p []byte) (int, error) {
    n, err := pt.Reader.Read(p)
    if n > 0 {
        pt.total += int64(n)
        percentage := float64(pt.total) / float64(pt.length) * float64(100)
        i := int(percentage / float64(10))
        is := fmt.Sprintf("%v", i)
        if percentage-pt.progress > 2 {
            fmt.Fprintf(os.Stderr, is)
            pt.progress = percentage
        }
    }

    return n, err
}
client := &http.Client{
    CheckRedirect: redirectPolicyFunc,
}
response, err := client.Get("http://example.com/something/large.zip")
defer response.Body.Close()
readerpt := &PassThru{Reader: response.Body, length: response.ContentLength}
body, err := ioutil.ReadAll(readerpt)