182 lines
7.6 KiB
Markdown
182 lines
7.6 KiB
Markdown
# TransferSu - 统一文件传输工具
|
||
|
||
基于 rsync / rclone / pv+tar 的统一拷贝管理工具,CLI/TUI 双模式,实时日志轮转,
|
||
专为"读卡器掉卡"等不稳定传输场景设计。
|
||
|
||
## 特性
|
||
|
||
- **多后端**: rsync(推荐, 断点续传)/ rclone(并行)/ pv+tar(零依赖)
|
||
- **CLI/TUI 双模式**: 未显式 `--mode cli` 时默认 TUI 启动
|
||
- **TUI 四栏布局**:
|
||
- 上栏: 总进度条(字节) + 单文件进度条(文件计数)
|
||
- 中栏: 速度曲线可视化(当前/峰值/平均速度实时文字)
|
||
- 下栏: 文件日志 + 错误日志 双面板
|
||
- 底部: 交互输入栏(空启动设定任务 / 传输控制命令)
|
||
- **进度轮询机制**: 每秒主动统计目标目录大小驱动进度,
|
||
绕过后端输出缓冲(Android 上 stdbuf/LD_PRELOAD 无效,rsync 输出全缓冲不可靠)
|
||
- **掉卡自愈**: `--retry -1` 无限自动补传 + 完成后 `--verify` 校验
|
||
- **实时日志**: 写入本地目录, 滚动保留最近 N 个(默认 20), 纳秒时间戳排序
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
pip install -i https://mirrors.aliyun.com/pypi/simple/ pytest textual
|
||
```
|
||
|
||
## 用法
|
||
|
||
```bash
|
||
# TUI 模式 (默认): 空启动后在底部输入栏设定任务
|
||
python3 transfer.py
|
||
|
||
# TUI 模式带预设任务
|
||
python3 transfer.py /src /dst --bwlimit 30000
|
||
|
||
# CLI 模式 (显式指定)
|
||
python3 transfer.py --mode cli /src/ /dst/ --backend rclone --bwlimit 8M
|
||
```
|
||
|
||
### TUI 输入栏命令
|
||
|
||
```
|
||
/src /dst --bwlimit 30000 --retry -1 --verify # 启动传输任务
|
||
stop # 停止当前任务 (SIGTERM, 跳过补传)
|
||
pause # 暂停 (SIGSTOP, 轮询同步挂起)
|
||
continue # 恢复暂停 (SIGCONT)
|
||
help / clear / quit
|
||
```
|
||
|
||
进度显示:
|
||
- 总进度条: 已传字节/源总量(每秒轮询刷新)
|
||
- 单文件进度条: **文件计数**(目标文件数/源文件总数, 每 3 秒刷新)
|
||
- 速度曲线栏: 当前/峰值/平均速度文字 + Sparkline 曲线
|
||
|
||
## 参数
|
||
|
||
| 参数 | 默认 | 说明 |
|
||
|---|---|---|
|
||
| `--backend` | rsync | rsync / rclone / tar |
|
||
| `--bwlimit` | 30000 | 限速 (rsync: KB/s, rclone: 如 8M) |
|
||
| `--transfers` | 4 | rclone 并行传输数 |
|
||
| `--resume` / `--no-resume` | 开 | rsync 断点续传 |
|
||
| `--checksum` | 关 | rsync 校验模式 |
|
||
| `--verify` | 关 | 传输完成后校验(等级由 `--verify-level` 决定) |
|
||
| `--verify-level` | slow | 校验等级: ultrafast/fast/normal/slow/full |
|
||
| `--check-only` | 关 | 纯校验模式: 不传输, 仅按等级校验源/目标 |
|
||
| `--repair` | 关 | 校验发现问题后提示并重传问题文件(先删目标避免增量盲区) |
|
||
| `--retry` | 0 | 失败自动补传轮数, **-1 = 无限重试** |
|
||
| `--smart-resume` | 关 | 智能续传: 校验目标最新N个文件, 损坏删除后从断点续传 |
|
||
| `--smart-check` | 5 | 智能续传校验文件数 (<=100MB 全校验, 更大只查大小) |
|
||
| `--policy` | overwrite | 冲突策略: overwrite / skip / ask |
|
||
| `--mode` | tui | cli / tui |
|
||
| `--keep-logs` | 20 | 日志滚动保留数 |
|
||
| `--logdir` | ~/logs | 日志目录 |
|
||
|
||
## 掉卡场景最佳实践
|
||
|
||
读卡器/移动硬盘在安卓上高速写入可能 USB 掉线(如 GL3224 芯片)。
|
||
完整方案:
|
||
|
||
1. **守护脚本**自动恢复设备(掉线后重枚举):
|
||
```bash
|
||
# 部署 (脚本在项目内 usb_guard.sh, 目标设备通用 VID/PID 可在脚本头部修改)
|
||
su -c 'cp ~/Proj/TransferSu/usb_guard.sh /data/local/tmp/ && chmod 755 /data/local/tmp/usb_guard.sh'
|
||
# 启动
|
||
su -c 'setsid sh /data/local/tmp/usb_guard.sh </dev/null >/dev/null 2>&1 &'
|
||
```
|
||
守护脚本功能: ① 应用稳定性调优参数 (SCSI 超时 120s 等)
|
||
② 三种掉线场景自动重枚举恢复 (dmesg 检测 / 异常断开 / 健康探测)。
|
||
默认绑定 GL3224 读卡器 (VID:PID 05e3:0747), 换设备改脚本头部变量。
|
||
开机自启: `~/.termux/boot/boot_usb_guard.sh` (Termux:Boot 插件)。
|
||
2. **限速传输 + 无限补传 + 校验**:
|
||
```
|
||
/src/ /dst/ --bwlimit 30000 --retry -1 --verify
|
||
```
|
||
3. 掉卡时: 守护恢复设备 → TransferSu 自动重跑补传(`--partial` 只补缺失)→
|
||
直到成功 → `rsync -c` 全量校验(0 差异 = 源目标完全一致)
|
||
|
||
**智能续传(`--smart-resume`)**: 中断后重跑时,只校验目标**最新 N 个文件**
|
||
(`--smart-check N`,默认 5;≤100MB 做 md5 全校验,更大只查大小),
|
||
发现损坏立即删除该文件并从断点续传——避免对已传的 100+GB 全量重扫。
|
||
校验过程有**进度条**(总进度条复用)+ **单文件日志**(`校验 i/N: 文件名 ✓/✘ 损坏`),
|
||
N 调大(如 50)也能实时看到校验进展。
|
||
|
||
### 校验等级(`--verify-level`)
|
||
|
||
| 等级 | 校验内容 | 188GB 耗时 | 适用 |
|
||
|---|---|---|---|
|
||
| `ultrafast` | 仅文件大小 | 秒级 | 快速健康检查 |
|
||
| `fast` | 大小+mtime | ~1 分钟 | 常规检查 |
|
||
| `normal` | 大小+mtime+最新N个md5 | 分钟级 | 兼顾速度与深度 |
|
||
| `slow` | 全部文件 md5 | 40-60 分钟 | 全量可靠(默认) |
|
||
| `full` | 全部md5+文件数对比 | 最慢 | 终极确认 |
|
||
|
||
**纯校验模式(`--check-only`)**: 不传输,只按等级校验源/目标一致性,
|
||
用于传输中断后快速确认已传数据是否完好:
|
||
|
||
```bash
|
||
# 快速检查已传数据(秒级)
|
||
python3 transfer.py --mode cli --check-only --verify-level ultrafast /src/ /dst/
|
||
# 全量校验已传数据(全部 md5)
|
||
python3 transfer.py --mode cli --check-only --verify-level slow /src/ /dst/
|
||
# 校验发现问题自动提示重传(--repair)
|
||
python3 transfer.py --mode cli --check-only --verify-level slow --repair /src/ /dst/
|
||
```
|
||
|
||
> `--repair`: 校验发现问题文件后提示 [y/N],确认后用 rsync 重传问题文件。
|
||
> 重传前**先删除目标问题文件**——避免 rsync 按 size+mtime 判定相同而跳过
|
||
> (内容损坏但大小/时间戳一致的场景,增量检测有盲区)。
|
||
> 重传完成后**自动复核**:用前置校验等级(`--verify-level`)对重传文件
|
||
> 再校验一遍,确认修复成功(日志记录 `复核通过 X 个 / 失败 Y 个`)。
|
||
|
||
> rsync 原子写(临时文件+rename)保证掉卡不会产生半截损坏的正式文件,
|
||
> 残留临时文件由补传后的 `--verify` 流程发现处理。
|
||
|
||
## 日志
|
||
|
||
- 目录: `--logdir` 指定(默认 `~/logs`)
|
||
- 文件名: `{时间戳}_{后端}_{源名}.log`(时间戳开头, 排序即时间序)
|
||
- 滚动: 超过 `--keep-logs` 个自动删除最旧
|
||
- 内容: 命令/源大小/补传轮次/退出码(含帧数)/校验结果/错误行
|
||
|
||
## 冲突策略(覆盖/跳过)
|
||
|
||
| 参数 | 行为 |
|
||
|---|---|
|
||
| `--overwrite` | 覆盖已存在文件(默认) |
|
||
| `--skip` | 跳过已存在文件(`--ignore-existing`) |
|
||
| `--ask` | 逐项询问(扫描冲突后交互) |
|
||
|
||
**ask 交互选项**(CLI 与 TUI 一致):
|
||
|
||
```
|
||
y = 覆盖当前项 n = 跳过当前项
|
||
a = 全部覆盖 s = 全部跳过
|
||
q = 中止传输
|
||
```
|
||
|
||
- **CLI**: 预扫描后逐项提示
|
||
- **TUI**: 扫描完成后在底部输入栏逐项交互
|
||
- **仅当前/后续同步**: y/n 只作用当前文件; a/s 一次决定后续(已明确决策的保留)
|
||
- rsync 覆盖场景自动禁用 `--append`(追加模式阻止重写), 保留 `--partial`
|
||
- rclone 的 `--ask` 用原生 `--interactive`(y/n/s); tar 后端不支持 ask/skip
|
||
|
||
```bash
|
||
# CLI 示例
|
||
python3 transfer.py --mode cli --policy ask --retry 5 --verify /src/ /dst/
|
||
python3 transfer.py --mode cli --retry -1 --verify /src/ /dst/
|
||
|
||
# TUI 输入栏示例
|
||
/src /dst --policy ask --retry 5 --verify
|
||
/src /dst --retry -1 --verify
|
||
```
|
||
|
||
## 测试
|
||
|
||
```bash
|
||
python3 -m pytest tests/ -q
|
||
```
|
||
|
||
54 个单元测试: 解析器 / 日志轮转 / 参数解析 / 后端命令 / 冲突决策 /
|
||
目录轮询 / 暂停信号 / 校验命令。
|