Files
ProjectOctopus/agent-wdd/utils/DownloadUtils.go
2025-02-27 17:19:36 +08:00

112 lines
2.5 KiB
Go

package utils
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
func DownloadFile(url string, path string) (bool, string) {
// 创建HTTP客户端
client := &http.Client{
Timeout: 5 * time.Second,
}
return DownloadFileWithClient(client, url, path)
}
func DownloadFileWithClient(client *http.Client, url string, path string) (bool, string) {
return downloadWithProgress(client, url, path)
}
// 带进度显示的下载函数
func downloadWithProgress(client *http.Client, url, dest string) (bool, string) {
// 创建目标文件
file, err := os.Create(dest)
if err != nil {
return false, fmt.Sprintf("创建文件失败: %w", err)
}
defer file.Close()
// 发起请求
resp, err := client.Get(url)
if err != nil {
return false, fmt.Sprintf("HTTP请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return false, fmt.Sprintf("服务器返回错误状态码: %s", resp.Status)
}
// 获取文件大小
size := resp.ContentLength
var downloaded int64
// 打印下载信息
fmt.Printf("开始下载: %s 大小: %s\n", url, HumanSizeInt(size))
// 创建带进度跟踪的Reader
progressReader := &progressReader{
Reader: resp.Body,
Reporter: func(r int64) {
downloaded += r
printProgress(downloaded, size)
},
}
// 执行拷贝
if _, err := io.Copy(file, progressReader); err != nil {
return false, fmt.Sprintf("文件拷贝失败: %w", err)
}
fmt.Print("\n") // 保持最后进度显示的完整性
return true, fmt.Sprintf("文件下载成功: %s", dest)
}
// 进度跟踪Reader
type progressReader struct {
io.Reader
Reporter func(r int64)
}
func (pr *progressReader) Read(p []byte) (int, error) {
n, err := pr.Reader.Read(p)
if n > 0 {
pr.Reporter(int64(n))
}
return n, err
}
// 打印进度信息
func printProgress(downloaded, total int64) {
const barLength = 40
percent := float64(downloaded) / float64(total) * 100
// 生成进度条
filled := int(barLength * downloaded / total)
bar := fmt.Sprintf("[%s%s]",
strings.Repeat("=", filled),
strings.Repeat(" ", barLength-filled))
// 格式化为人类可读大小
humanSize := func(bytes int64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%d B", bytes)
}
div, exp := int64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %ciB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
fmt.Printf("\r%-45s %6.2f%% %s/%s", bar, percent,
humanSize(downloaded), humanSize(total))
}