via:
https://returnfn.com/lets-build-a-concurrent-file-downloader-in-go 作者:Mostafa Asgari
今天给大家分享一个实战项目,涉及到的知识点还挺多,文末也有源码地址!!
原文如下:
Go 语言是一门了不起的语言,尽管它非常简单,与 Koltin 和 Scala 等其他现代语言相比,它的功能很少,但它具有强大的并发能力。这篇文章,我们将会看到使用 Go 语言如何编写一个完整的并发文件下载器。完整的代码在这里[1]。
检查服务器是否支持并发下载
如何之前使用过类似 IDM 的下载工具,你可能会注意到它支持并发下载文件。
可以看到下载文件的时候启动了 8 个进程。
实现并发下载,我们必须确保服务器支持范围请求。怎么确认呢?我们可以发送 HEAD 请求,如果响应头的 Accept-Ranges 返回的值是 bytes,我们就能确定服务器支持此功能。
如何下载文件的其中一部分
设想服务器支持范围请求,我们知道文件大小是 4000 字节(文件大小从响应头的 Content-Length 获取)。要仅下载 2000 到 3000 字节的文件的一部分,我们可以发送 HTTP GET 请求,并在 header 头设置 Range 参数:
实现相同功能的代码如下:
将响应保存在文件中
为了支持断点续传功能,我们不会将请求响应保存在内存里,而是会持久化在文件中。举个例子,如果我们把并发级别设置成 4,在输出目录将会有 4 个临时文件。下面的代码,我们只是简单地读取 HTTP 响应体并将它写入一个文件中:
暂停下载
不知道大家注意到没有,上面代码有个问题,使用时不支持 CTRL+C 暂停下载。如果下载的文件过大,或者网络慢,下载需要花费很长时间。因为 io.Copy 复制文件时遇到 EOF 或者发生错误才结束。为了解决这个问题,我们使用 io.CopyN 和 cancel channel 组合:
其他功能参见完整源代码
这篇文章只提到了代码中最重要的部分,但是通过阅读代码你可以了解其他功能是怎么实现的,比如:进度条的工作方式、如何使用 sync 包实现部分下载的同步、如何合并临时文件以及如何实现恢复功能等。所以可以通过阅读仓库代码[2]获取更多信息。
参考资料
[1]
这里: https://github.com/mostafa-asg/go-dl
[2]
仓库代码: https://github.com/mostafa-asg/go-dl
这是持续翻译的第 26/100 篇优质文章。
如果你有想交流的话题,欢迎留言。
如果您的朋友也在学习 Go 语言,相信这篇文章对 TA 有帮助,欢迎转发分享给 TA,非常感谢!