Golang中如何实现下载文件进度跟踪

Golang中如何实现下载文件进度跟踪 如何跟踪从URL下载文件时的下载百分比或字节数。

10 回复

好的。

更多关于Golang中如何实现下载文件进度跟踪的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你有用来进行这个HTTP GET请求的代码吗?

他们在这里使用了第三方包。有没有办法只使用 Go 语言自带的包来实现呢?

谢谢。

如果使用了其他包,我必须告知下载我包的用户,他们必须拥有 http://github.com/dustin/go-humanize 这个包

github.com/dustin/go-humanize” 只是一个将字节数写成 kB、MB、GB 等单位的包。你不需要这个功能。

以下是humanize的一个非常精简的替代函数:

func humanFormat(bytes int64) string {
	n := float64(bytes)
	for _, unit := range []string{"", "Ki", "Mi", "Gi"} {
		if math.Abs(n) < 1024.0 {
			return fmt.Sprintf("%3.1f%sB", n, unit)
		}
		n /= 1024.0
	}
	return fmt.Sprintf("%.1fTiB", n)
}

这将检测操作系统并下载代码然后解压。但不会显示下载进度。

func DownloadFile(filepath string, url string) error {
    out, err := os.Create(filepath)
    if err != nil {
        return err
    }
    defer out.Close()
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()
    _, err = io.Copy(out, resp.Body)
    if err != nil {
        return err
    }
    return nil
}

Johan的意思是你可以修改这行代码来避免使用那个包:

// We use the humanize package to print the bytes in a meaningful way (e.g. 10 MB)
fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total))

你可以直接输出原始的字节数,或者编写自己的格式化函数来替代第三方调用,例如:

//Just print the bytes.
fmt.Printf("\rDownloading... %d complete", wc.Total)
//Or use your custom function.
fmt.Printf("\rDownloading... %s complete", yourFormatterFunction(wc.Total))

这样,除了标准库之外你就没有其他依赖了。

为什么要在只有这一行代码有意义的情况下,把所有代码都贴出来呢?

resp, err := http.Get(url)

这个函数是阻塞的。它会在完成 HTTP GET 请求后立即返回。

也许这篇博客文章能帮到你:

网站图标

第二部分)下载大文件并显示进度 - GolangCode

示例图片

我们已经介绍了文件下载的基础知识——这篇文章在此基础上通过包含下载进度报告来创建一个更完整的下载器。这意味着如果你正在下载大文件,你将能够看到下载的进度情况…

在Go语言中,可以通过自定义io.Reader包装器来跟踪下载文件的进度。以下是一个完整的示例,展示了如何从URL下载文件并实时显示下载百分比和字节数。

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
)

// 自定义Reader包装器,用于跟踪读取进度
type ProgressReader struct {
    io.Reader
    Total    int64
    Current  int64
    Progress func(current, total int64)
}

func (pr *ProgressReader) Read(p []byte) (int, error) {
    n, err := pr.Reader.Read(p)
    if n > 0 {
        pr.Current += int64(n)
        if pr.Progress != nil {
            pr.Progress(pr.Current, pr.Total)
        }
    }
    return n, err
}

func main() {
    url := "https://example.com/largefile.zip"
    outputPath := "downloaded_file.zip"

    // 发送HEAD请求获取文件大小
    resp, err := http.Head(url)
    if err != nil {
        fmt.Printf("Error getting file info: %v\n", err)
        return
    }
    defer resp.Body.Close()

    contentLength := resp.Header.Get("Content-Length")
    totalSize, err := strconv.ParseInt(contentLength, 10, 64)
    if err != nil {
        fmt.Printf("Error parsing content length: %v\n", err)
        return
    }

    // 发送GET请求下载文件
    resp, err = http.Get(url)
    if err != nil {
        fmt.Printf("Error downloading file: %v\n", err)
        return
    }
    defer resp.Body.Close()

    // 创建输出文件
    file, err := os.Create(outputPath)
    if err != nil {
        fmt.Printf("Error creating file: %v\n", err)
        return
    }
    defer file.Close()

    // 创建进度跟踪Reader
    progressReader := &ProgressReader{
        Reader: resp.Body,
        Total:  totalSize,
        Progress: func(current, total int64) {
            percentage := float64(current) / float64(total) * 100
            fmt.Printf("\rDownload progress: %.2f%% (%d/%d bytes)", percentage, current, total)
        },
    }

    // 复制数据到文件
    _, err = io.Copy(file, progressReader)
    if err != nil {
        fmt.Printf("\nError saving file: %v\n", err)
        return
    }

    fmt.Printf("\nDownload completed: %s\n", outputPath)
}

这个实现包含以下关键部分:

  1. ProgressReader结构体:包装原始io.Reader,在每次读取时更新进度
  2. 进度回调函数:实时显示下载百分比和字节数
  3. HEAD请求:预先获取文件总大小
  4. 进度显示:使用\r实现同一行更新进度信息

运行此代码时,会显示类似这样的进度:

Download progress: 45.67% (456700/1000000 bytes)

如果需要更精细的控制,可以修改Progress回调函数来实现:

  • 进度条显示
  • 下载速度计算
  • 分段下载跟踪
  • 多文件下载进度管理
回到顶部