C#实现云同步文件夹逻辑 C#如何设计一个类似Dropbox的本地文件同步代理

来源:这里教程网 时间:2026-02-21 17:43:04 作者:

同步代理的核心职责是什么

一个本地文件同步代理不是简单地复制粘贴文件,它要持续观察本地目录变化、比对云端状态、按需上传下载,并处理冲突和断点续传。关键在于:它必须区分「变更事件」和「最终状态」——

FileSystemWatcher
触发的
Changed
事件非常频繁且可能重复,不能直接拿它当同步指令;真正该同步的是文件内容哈希或最后修改时间戳确认过的终态。

同步粒度应基于文件元数据(大小 +
ETag
MD5
)而非仅靠时间戳,Windows 文件系统时间精度低,NFS 或虚拟机场景下容易误判
必须维护本地状态缓存(如 SQLite 数据库存储每个文件的
local_hash
remote_version
is_deleted
),否则每次启动都要全量扫描比对
所有网络操作必须带重试(指数退避)和取消令牌(
CancellationToken
),避免卡死整个代理进程

如何用 FileSystemWatcher 安全捕获真实变更

FileSystemWatcher
是入口,但默认配置极易漏事件或触发多次。它本身不保证事件顺序,也不合并连续写入(例如 Word 保存会触发 3–4 次
Changed
)。

设置
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
,禁用
FileName
DirectoryName
,减少重命名/移动带来的干扰
必须启用
IncludeSubdirectories = true
,但为避免递归监听导致句柄耗尽,建议只监听用户指定的根路径,子目录由程序逻辑遍历发现
对每个
Changed
事件,立刻启动一个带延时的去抖任务(例如
Task.Delay(1000, token)
),等静默期结束后再读取文件大小和哈希——这是避免“写一半就同步”的唯一可靠方式
删除事件(
Deleted
)需单独处理并记录到本地状态库,不能依赖后续扫描推断

上传/下载如何避免阻塞和重复

同步代理常因大文件上传卡住 UI 或拖慢扫描。所有 I/O 必须异步且可中断,同时防止同一文件被多次排队。

使用
HttpClient.PutAsync()
或分块
POST
上传,配合
IProgress<long></long>
更新进度,上传前先校验本地哈希是否已存在于云端(查
/api/v1/file/info?hash=xxx
下载使用
Range
请求支持断点续传,把临时文件写到
.sync_tmp_abc123
,完整校验哈希后再原子重命名为目标名
维护一个内存中
ConcurrentDictionary<string task></string>
(key 为文件相对路径),提交新任务前先
TryRemove
旧任务并
await
其完成,防止并发上传同一文件

冲突检测与用户干预点在哪

自动覆盖不是好策略。Dropbox 式行为是:当本地和云端都修改过同一文件,保留两者,生成类似

report.docx (Your Conflicted Copy 2024-05-22).docx
的副本。

冲突判定依据是:本地有修改(
local_hash != remote_hash
)且云端也有更新(
remote_version > local_version
不要尝试自动合并二进制文件,文本文件也仅在明确标记为
text/plain
且启用 diff 工具时才走合并逻辑
把冲突文件路径写入一个
conflicts.json
清单,供 GUI 层弹窗提示,或 CLI 输出警告行 —— 这个清单本身也要同步到云端,让多端知道“此处有未决冲突”

本地状态库结构稍复杂,但少它一天都跑不稳;哈希计算别图省事用

File.ReadAllBytes()
,大文件必须流式计算;还有,别忘了 Windows 上长路径(>260 字符)需要在
app.manifest
里启用
longPathAware

相关推荐

热文推荐