2015-05-29 68 views
2

我试图用golang文件下载。golang动态进度

我下载的文件也没关系。在我使用cheggaaa的进度条库之后。但我不能动态。

我该怎么办动态进度?

我下面的代码:

包主要

import (
    "flag" 
    "fmt" 
    "io" 
    "net/http" 
    "net/url" 
    "os" 
    "strings" 
    "github.com/cheggaaa/pb" 
    "time" 
) 

/* 
    usage = usage text 
    version = current number 
    help use Sprintf 
    *cliUrl from cmd 
    *cliVersion from cmd 
    *cliHelp * from cmd 
*/ 
var (
    usage  = "Usage: ./gofret -url=http://some/do.zip" 
    version = "Version: 0.1" 
    help  = fmt.Sprintf("\n\n %s\n\n\n %s", usage, version) 
    cliUrl  *string 
    cliVersion *bool 
    cliHelp *bool 
) 

func init() { 
    /* 
     if *cliUrl != "" { 
      fmt.Println(*cliUrl) 
     } 

     ./gofret -url=http://somesite.com/somefile.zip 
     ./gofret -url=https://github.com/aligoren/syspy/archive/master.zip 
    */ 
    cliUrl = flag.String("url", "", usage) 

    /* 
     else if *cliVersion{ 
      fmt.Println(flag.Lookup("version").Usage) 
     } 

     ./gofret -version 
    */ 
    cliVersion = flag.Bool("version", false, version) 

    /* 
     if *cliHelp { 
      fmt.Println(flag.Lookup("help").Usage) 
     } 

     ./gofret -help 
    */ 
    cliHelp = flag.Bool("help", false, help) 
} 

func main() { 

    /* 
     Parse all flags 
    */ 
    flag.Parse() 

    if *cliUrl != "" { 
     fmt.Println("Downloading file") 

     /* parse url from *cliUrl */ 
     fileUrl, err := url.Parse(*cliUrl) 

     if err != nil { 
      panic(err) 
     } 

     /* get path from *cliUrl */ 
     filePath := fileUrl.Path 

     /* 
      seperate file. 
      http://+site.com/+(file.zip) 
     */ 
     segments := strings.Split(filePath, "/") 

     /* 
      file.zip filename lenth -1 
     */ 
     fileName := segments[len(segments)-1] 

     /* 
      Create new file. 
      Filename from fileName variable 
     */ 
     file, err := os.Create(fileName) 

     if err != nil { 
      fmt.Println(err) 
      panic(err) 
     } 
     defer file.Close() 

     /* 
      check status and CheckRedirect 
     */ 
     checkStatus := http.Client{ 
      CheckRedirect: func(r *http.Request, via []*http.Request) error { 
       r.URL.Opaque = r.URL.Path 
       return nil 
      }, 
     } 

     /* 
      Get Response: 200 OK? 
     */ 
     response, err := checkStatus.Get(*cliUrl) 

     if err != nil { 
      fmt.Println(err) 
      panic(err) 
     } 
     defer response.Body.Close() 
     fmt.Println(response.Status) // Example: 200 OK 

     /* 
      fileSize example: 12572 bytes 
     */ 
     fileSize, err := io.Copy(file, response.Body) 
     /* 
      progressbar worked after download :(
     */ 
     var countSize int = int(fileSize/1000) 
     count := countSize 
     bar := pb.StartNew(count) 
     for i := 0; i < count; i++ { 
      bar.Increment() 
      time.Sleep(time.Millisecond) 
     } 
     bar.FinishPrint("The End!") 

     if err != nil { 
      panic(err) 
     } 


     fmt.Printf("%s with %v bytes downloaded", fileName, count) 

    } else if *cliVersion { 
     /* 
      lookup version flag's usage text 
     */ 
     fmt.Println(flag.Lookup("version").Usage) 
    } else if *cliHelp { 
     /* 
      lookup help flag's usage text 
     */ 
     fmt.Println(flag.Lookup("help").Usage) 
    } else { 
     /* 
      using help's usage text for handling other status 
     */ 
     fmt.Println(flag.Lookup("help").Usage) 
    } 
} 

虽然我的程序运行:

Downloading file 
200 OK 

下载工作进度后:

6612/6612 [=====================================================] 100.00 % 7s 
The End! 
master.zip with 6612 bytes downloaded 

我progressb ar代码如下:

/* 
    progressbar worked after download :(
*/ 
var countSize int = int(fileSize/1000) 
count := countSize 
bar := pb.StartNew(count) 
for i := 0; i < count; i++ { 
    bar.Increment() 
    time.Sleep(time.Millisecond) 
} 
bar.FinishPrint("The End!") 

我该如何解决进度条问题?

+1

你甚至在开始进度条之前下载文件。 – JimB

+0

@JimB我试过,但没有工作,因为我得到fileSize未定义的错误 – Ali

回答

6

更够程。刚刚阅读吧

// start new bar 
bar := pb.New(fileSize).SetUnits(pb.U_BYTES) 
bar.Start() 
// create proxy reader 
rd := bar.NewProxyReader(response.Body) 
// and copy from reader 
io.Copy(file, rd) 
3

我写了下面的东西,到进度它是正确的在一般情况下,不相关,但该库正是设计来处理这个问题,有专门支持它,并给出了一个explicit example of downloading a file


您需要在更新进度条的同时运行下载,目前您正在下载整个文件,然后更新进度条。

这是一个有点草率,但应该让你在正确的方向前进:

首先,抢预期文件大小:

filesize := response.ContentLength 

然后开始下载一个够程:

go func() { 
     n, err := io.Copy(file, response.Body) 
     if n != filesize { 
      log.Fatal("Truncated") 
     } 
     if err != nil { 
      log.Fatalf("Error: %v", err) 
     } 
    }() 

然后更新您的进度栏,因为它沿着:

countSize := int(filesize/1000) 
    bar := pb.StartNew(countSize) 
    var fi os.FileInfo 
    for fi == nil || fi.Size() < filesize { 
     fi, _ = file.Stat() 
     bar.Set(int(fi.Size()/1000)) 
     time.Sleep(time.Millisecond) 
    } 
    bar.FinishPrint("The End!") 

就像我说的,这是一点不马虎;您可能希望根据文件的大小更好地调整条形,并且log.Fatal调用很难看。但它处理了这个问题的核心。

或者,你可以通过编写自己的io.Copy版本做到这一点没有一个够程。从response.Body中读取一个块,更新进度条,然后将块写入file。这可以说是更好,因为你可以避免睡眠呼叫。不需要

+0

这是行得通!谢谢。现在在GitHub上的源代码: https://gist.github.com/aligoren/9426249fa8cd04c4633e – Ali