Linux curl分段下载大文件并校验完整性的实现
来源:17golang原创
时间:2026-09-20 16:00:00 132浏览 收藏
Linux 上处理几个 GB 甚至更大的文件时,可以把文件按字节区间拆成多个片段,用 curl --range 分别保存,再按顺序合并。真正决定结果是否可靠的不是“命令执行完了”,而是每段都返回了预期范围、合并后的字节数正确,并且最终 SHA-256 摘要与发布方提供的值一致。
官方文档:https://curl.se/docs/manpage.html
推荐把“分段下载、片段检查、顺序合并、摘要校验”做成一个有失败出口的脚本。只要服务端忽略 Range 返回 200,就立即停止,不能把完整响应误当成某一段。
先确认 curl 分段下载的前提
--range start-end 表示请求指定的字节范围,例如 0-1048575 是前 1 MiB。curl 官方手册也提醒,部分 HTTP 服务端不支持 Range,收到请求后会直接返回完整文件;这时响应通常是 200,而不是 206 Partial Content。--continue-at 是从已有文件偏移处续传,和 --range 不能在一次传输中混用,二者不要混成一个恢复逻辑。
因此,脚本至少需要三个已知量:下载地址、文件总长度 total、分片大小 chunk。总长度应来自可信的发布清单或已确认的响应头,不要用一次失败下载得到的本地大小反推。

固定边界并检查每个片段
下面的脚本采用顺序下载,便于排查。每一段的结束位置是 start + chunk - 1,最后一段再限制为 total - 1。保存片段前检查 HTTP 状态,保存后检查实际字节数,两个条件任何一个不满足都退出。
#!/usr/bin/env bash # 这段脚本按固定字节区间下载,并拒绝服务端忽略 Range 的响应。 set -euo pipefail url="https://mirror.example.org/releases/demo.tar.zst" total=838860800 # 这里填写已确认的总字节数,不用本地文件大小猜测 chunk=$((64 * 1024 * 1024)) # 每段 64 MiB,按网络和磁盘情况调整 work="demo.parts" output="demo.tar.zst" mkdir -p "$work" : > "$work/parts.list" # 清空旧清单,避免混入上一次失败的片段 for ((start=0; start= total )) && end=$((total - 1)) part="$work/part-${start}-${end}" header="$part.headers" # --fail 遇到HTTP错误退出;--range只请求当前闭区间。 curl --fail --show-error --location \ --range "${start}-${end}" \ --dump-header "$header" \ --output "$part" "$url" # Range成功应得到206;否则说明服务端可能返回了整文件,立即停止。 status=$(awk '/^HTTP\// { code=$2 } END { print code }' "$header") [[ "$status" == "206" ]] || { echo "Range未生效: HTTP $status" >&2; exit 1; } expected=$((end - start + 1)) actual=$(wc -c &2; exit 1; } printf '%s\n' "$part" >> "$work/parts.list" done
按清单合并并做两层确认
下载成功不代表最终文件正确。合并时只读取当前清单中的片段,并用追加模式保持顺序;随后先比较字节数,再比较摘要。字节数能较快发现漏段或重复段,摘要则能发现内容被替换、截断但长度碰巧相同等问题。
# 只按下载阶段写入的顺序合并,避免通配符排序改变片段次序。 rm -f "$output" while IFS= read -r part; do cat "$part" >> "$output" done &2 exit 1 } # checksum.txt 的格式必须是“摘要 空格 文件名”,供 sha256sum -c 读取。 sha256sum "$output" > "$work/local.sha256" sha256sum -c checksum.txt echo "下载、合并和SHA-256校验完成: $output"
如果发布方只给出一串摘要,也可以先生成本地结果,再用 sha256sum 的输出比较;不要把摘要写进未经确认的 checksum.txt 后再对自己生成的文件做“自证”。摘要文件应来自发布方、镜像目录或签名清单。

失败时按证据定位,不要盲目重试
看到 200 时,先确认服务端是否支持 Range、重定向后的地址是否改变,以及代理是否移除了 Range 请求。看到片段长度不符时,检查是否遇到压缩传输、服务端动态内容或边界计算错误;不要直接把响应追加到最终文件。若只有某一段失败,可以删除该段及其响应头后重新下载,但要再次检查状态、长度和清单顺序。
如果最终摘要失败,优先对比片段清单和总字节数,再逐段重新计算摘要,定位是漏段、重复段还是源文件本身已经更新。下载过程中源文件发生变化时,即使每段都是 206,拼出来的文件也可能没有任何一个稳定版本的摘要;此时应固定版本 URL 或使用带版本标识的发布清单。
速查清单与常见疑问
- Range 生效:每段响应为 206,且实际字节数等于
end-start+1。 - 边界无重叠:第一段从 0 开始,最后一段结束于
total-1。 - 合并可复现:使用固定清单,不依赖目录通配符顺序。
- 校验可信:摘要来自发布方,不能用本地刚生成的摘要代替。
curl 不支持 Range 怎么办?这通常不是 curl 参数写错,而是服务端没有启用字节范围,或中间代理改变了响应。改用普通下载或更换支持 Range 的镜像,并保留完整性校验。
为什么不直接用 -C -?--continue-at适合单文件断点续传;需要并行、重试单段或保存每段证据时,显式的 Range 清单更容易控制边界和恢复。
-
426 收藏
-
387 收藏
-
242 收藏
-
238 收藏
-
402 收藏
-
403 收藏
-
293 收藏
-
220 收藏
-
495 收藏
-
496 收藏
-
204 收藏
-
302 收藏
-
234 收藏
-
104 收藏
-
253 收藏
-
204 收藏
-
451 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习