登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

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。总长度应来自可信的发布清单或已确认的响应头,不要用一次失败下载得到的本地大小反推。

curl按字节起止位置拆分大文件的静态结构说明图
图1:curl Range 字节边界说明图,展示连续片段如何覆盖完整文件;这是静态结构图,不是运行截图。

固定边界并检查每个片段

下面的脚本采用顺序下载,便于排查。每一段的结束位置是 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 后再对自己生成的文件做“自证”。摘要文件应来自发布方、镜像目录或签名清单。

Linux分片合并后先比较字节数再验证SHA-256的结构说明图
图2:片段清单、顺序合并、字节数检查和 SHA-256 校验的关系图;这是静态结构图,不是运行截图。

失败时按证据定位,不要盲目重试

看到 200 时,先确认服务端是否支持 Range、重定向后的地址是否改变,以及代理是否移除了 Range 请求。看到片段长度不符时,检查是否遇到压缩传输、服务端动态内容或边界计算错误;不要直接把响应追加到最终文件。若只有某一段失败,可以删除该段及其响应头后重新下载,但要再次检查状态、长度和清单顺序。

如果最终摘要失败,优先对比片段清单和总字节数,再逐段重新计算摘要,定位是漏段、重复段还是源文件本身已经更新。下载过程中源文件发生变化时,即使每段都是 206,拼出来的文件也可能没有任何一个稳定版本的摘要;此时应固定版本 URL 或使用带版本标识的发布清单。

速查清单与常见疑问

  • Range 生效:每段响应为 206,且实际字节数等于 end-start+1
  • 边界无重叠:第一段从 0 开始,最后一段结束于 total-1
  • 合并可复现:使用固定清单,不依赖目录通配符顺序。
  • 校验可信:摘要来自发布方,不能用本地刚生成的摘要代替。

curl 不支持 Range 怎么办?这通常不是 curl 参数写错,而是服务端没有启用字节范围,或中间代理改变了响应。改用普通下载或更换支持 Range 的镜像,并保留完整性校验。

为什么不直接用 -C ---continue-at适合单文件断点续传;需要并行、重试单段或保存每段证据时,显式的 Range 清单更容易控制边界和恢复。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>