Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to print the bytes while the file is being downloaded ? -golang

Tags:

go

byte

I'm wondering if it's possible to count and print the number of bytes downloaded while the file is being downloaded.

out, err := os.Create("file.txt")
defer out.Close()
if err != nil {
    fmt.Println(fmt.Sprint(err))
    panic(err)
}
resp, err := http.Get("http://example.com/zip")
defer resp.Body.Close()
if err != nil {
    fmt.Println(fmt.Sprint(err))
    panic(err)
}

n, er := io.Copy(out, resp.Body)
if er != nil {
    fmt.Println(fmt.Sprint(err))
}
fmt.Println(n, "bytes ")
like image 914
The user with no hat Avatar asked Mar 15 '14 08:03

The user with no hat


People also ask

How can I see the size of a file while downloading?

you can get a header called Content-Length form the HTTP Response object that you get, this will give you the length of the file. you should note though, that some servers don't return that information, and the only way to know the actual size is to read everything from the response.

How do you print the size of a file in Python?

stat() method returns the statistics of a file such as metadata of a file, creation or modification date, file size, etc. Next, use the os. stat('file_path') method to get the file statistics. At the end, use the st_size attribute to get the file size.

How do I make Python download faster?

The first thing to do is to use HTTP/2.0 and keep one conection open for all the files with Keep-Alive. The easiest way to do that is to use the Requests library, and use a session. If this isn't fast enough, then you need to do several parallel downloads with either multiprocessing or threads.


2 Answers

The stdlib now provides something like jimt's PassThru: io.TeeReader. It helps simplify things a bit:

// WriteCounter counts the number of bytes written to it.
type WriteCounter struct {
    Total int64 // Total # of bytes transferred
}

// Write implements the io.Writer interface.  
// 
// Always completes and never returns an error.
func (wc *WriteCounter) Write(p []byte) (int, error) {
    n := len(p)
    wc.Total += int64(n)
    fmt.Printf("Read %d bytes for a total of %d\n", n, wc.Total)
    return n, nil
}

func main() {

    // ...    

    // Wrap it with our custom io.Reader.
    src = io.TeeReader(src, &WriteCounter{})

    // ...
}

playground

like image 106
Dave Jack Avatar answered Oct 18 '22 12:10

Dave Jack


If I understand you correctly, you wish to display the number of bytes read, while the data is transferring. Presumably to maintain some kind of a progress bar or something. In which case, you can use Go's compositional data structures to wrap the reader or writer in a custom io.Reader or io.Writer implementation.

It simply forwards the respective Read or Write call to the underlying stream, while doing some additional work with the (int, error) values returned by them. Here is an example you can run on the Go playground.

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
    "strings"
)

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

// 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)
    pt.total += int64(n)

    if err == nil {
        fmt.Println("Read", n, "bytes for a total of", pt.total)
    }

    return n, err
}

func main() {
    var src io.Reader    // Source file/url/etc
    var dst bytes.Buffer // Destination file/buffer/etc

    // Create some random input data.
    src = bytes.NewBufferString(strings.Repeat("Some random input data", 1000))

    // Wrap it with our custom io.Reader.
    src = &PassThru{Reader: src}

    count, err := io.Copy(&dst, src)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    fmt.Println("Transferred", count, "bytes")
}

The output it generates is this:

Read 512 bytes for a total of 512
Read 1024 bytes for a total of 1536
Read 2048 bytes for a total of 3584
Read 4096 bytes for a total of 7680
Read 8192 bytes for a total of 15872
Read 6128 bytes for a total of 22000
Transferred 22000 bytes
like image 39
jimt Avatar answered Oct 18 '22 13:10

jimt