2014-09-03 3 views
3

전달 된 url 매개 변수를 통해 파일을 다운로드하는 프로세스를 수행 중입니다. 다운로드가 제대로 수행되고 있지만 수행 할 수없는 일은 다운로드 완료 비율에 대한 요약을 인쇄하는 것입니다. (1 초마다)파일 다운로드 및 요약보기 (백분율) - go go

필자는이 요약본을 시뮬레이션 한 종류로 만들었지 만, 다운로드하지 않은 것은 단지 그것을 원하는 방식으로 보여줍니다.

복사가 완료되는 동안 ant 인쇄를 변경할 수 있도록 원본에서 io.copy를 가져 오려고했으나 실패합니다.

누군가 나를 도울 수 있습니까? 감사

package main 

    import (
     "fmt" 
     "io" 
     "net/http" 
     "os" 
     "strings" 
    // "time" 
    ) 

    func downloadFromUrl(url string) { 
     tokens := strings.Split(url, "/") 
     fileName := tokens[len(tokens)-1] 
     fmt.Println("Downloading", url, "to", fileName) 

    //create file 
    output, err := os.Create(fileName) 
    if err != nil { 
     fmt.Println("Error while creating", fileName, "-", err) 
     return 
    } 
    fmt.Println("Creating", fileName) 
    defer output.Close() 

    //get url 
    response, err := http.Get(url) 
    if err != nil { 
     fmt.Println("Error while downloading", url, "-", err) 
     return 
    }   
    defer response.Body.Close() 

    //copy and bytes   
    n, err := io.Copy(output, response.Body) 
    if err != nil { 
     fmt.Println("Error while downloading", url, "-", err) 
     return 
    } 

     //track progress 
     for i := 1; float64(i) < float64(n); i++ { 
      fmt.Println("",float64(i),float64(n)) 
      percent := float64(i)/(float64(n)/float64(100)) 
      percentTot := fmt.Sprintf(" %#.02f%% ", percent) 
      fmt.Println(percentTot,"downloaded\n") 
      //time.Sleep(3000 * time.Millisecond) 
     } 


    } 

    func main() { 
     //read args 
     args := os.Args 

     //loop args 
     for i := 1; i < len(args); i++ { 
      url := args[i] 
      //call download   
      downloadFromUrl(url)   
     } 
    } 


**Output:** 
go run main.go http://download.geonames.org/export/dump/AD.zip 
Downloading http://download.geonames.org/export/dump/AD.zip to AD.zip 
Creating AD.zip 
1 64639 
0.00% downloaded 

2 64639 
0.00% downloaded 

3 64639 
0.00% downloaded 

4 64639 
0.01% downloaded 

5 64639 
0.01% downloaded 

답변

6

내가

// 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 래퍼 내 senvgo project에 그 짓을

// 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 
} 

(그에게 io.Reader를 만들기 위해) 그리고 그 io.Reader을 사용하여 Response을 읽습니다. HTTP 요청) :

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) 

ReadAll() 호출은 실제 다운로드를 트리거하고 PassThru.Read()가 예상되는 길이 (response.ContentLength)


영감에 다운로드 % 인쇄됩니다 :

+1

만약'err == nil'이라면'n == 0'이라고 가정하는 것 같습니다. 반드시 그런 것은 아닙니다. [Package io type Reader] (http://golang.org/pkg/io/#Reader) : 읽기는 최대 len (p) 바이트를 p로 읽습니다. 읽은 바이트 수 (0 <= n <= len (p))와 발생한 오류를 반환합니다. – peterSO

+0

@peterSO 위의 코드에서'err == nil'이면'n == 0'을 어디서 볼 수 있습니까? – VonC

+0

'func (pt * PassThru) 읽기 (p [] 바이트) (int, error)'에 err == nil {pt.total + = int64 (n)}'이 있습니다. 'err! = nil'이라면'pt.total'에'n'을 추가하지 마십시오. – peterSO