实现思路:
文件分割: 将目标文件分割成多个大小相等的块(例如 10MB/块)。 并发下载: 为每个文件块创建一个 goroutine,每个 goroutine 负责下载对应块的内容并保存到临时文件中。 同步与合并: 使用 channel 来同步所有 goroutine 的下载进度,并在所有块下载完成后,按顺序合并所有临时文件,最终得到完整的原始文件。
代码示例:
package main import (
"fmt" "io" "net/http" "os" "sync" ) func main() {
url := "https://example.com/large_file.zip" // 目标文件 URL filePath := "large_file.zip" // 下载后的文件名 chunkSize := 10 * 1024 * 1024 // 每个块的大小:10MB downloadFile(url, filePath, chunkSize)
} func downloadFile(url, filePath string, chunkSize int) {
// 获取文件大小 resp, _ := http.Head(url)
fileSize := int(resp.ContentLength)
// 计算块的数量 chunkCount := (fileSize + chunkSize - 1) / chunkSize
// 创建 channel 用于同步下载进度 done := make(chan bool, chunkCount)
// 使用 WaitGroup 等待所有 goroutine 完成 var wg sync.WaitGroup
wg.Add(chunkCount)
// 并发下载文件块 for i := 0; i < chunkCount; i++ {
go func(i int) {
defer wg.Done()
start := i * chunkSize
end := (i + 1) * chunkSize
if end > fileSize {
end = fileSize
}
downloadChunk(url, filePath, i, start, end)
done <- true }(i)
}
// 等待所有块下载完成 go func() {
wg.Wait()
close(done)
}()
// 合并文件块 mergeChunks(filePath, chunkCount)
} func downloadChunk(url, filePath string, chunkId, start, end int) {
// 创建 HTTP 请求 req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end-1))
// 发送请求并下载文件块 resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
// 创建临时文件 tmpFile, _ := os.Create(fmt.Sprintf("%s.part%d", filePath, chunkId))
defer tmpFile.Close()
// 将下载内容写入临时文件 io.Copy(tmpFile, resp.Body)
} func mergeChunks(filePath string, chunkCount int) {
// 创建最终文件 finalFile, _ := os.Create(filePath)
defer finalFile.Close()
// 按顺序合并所有临时文件 for i := 0; i < chunkCount; i++ {
tmpFileName := fmt.Sprintf("%s.part%d", filePath, i)
tmpFile, _ := os.Open(tmpFileName)
defer tmpFile.Close()
io.Copy(finalFile, tmpFile)
os.Remove(tmpFileName) // 删除临时文件 }
}
考点分析:
GMP 模型: 代码中使用 goroutine 来实现并发下载,充分利用了 Golang 的多核优势。 Channel: 使用 channel 来同步下载进度,确保所有块下载完成后再进行合并操作。 WaitGroup: 使用 WaitGroup 来等待所有 goroutine 完成,避免主线程提前退出。 错误处理: 实际应用中需要添加更完善的错误处理机制。