使用Renci.sshnet开发C# SFTP下载接口:如何判断文件是否正在上传
解决SFTP上传中文件无法下载的判断问题
嘿,这个场景我之前做项目时碰到过,给你几个靠谱的解决方案,都是基于Renci.SshNet能实现的:
方案1:检查文件大小是否稳定
上传中的文件大小肯定是持续增长的,我们可以间隔一段时间两次获取文件大小,如果连续两次大小一致,基本就能确定上传完成了。这是最通用的方法,不依赖服务器的特殊配置。
示例代码:
private bool IsFileUploadComplete(SftpClient sftpClient, string remoteFile, int checkIntervalMs = 2000, int maxChecks = 3) { long lastSize = -1; int stableCount = 0; for (int i = 0; i < maxChecks; i++) { var fileAttr = sftpClient.GetAttributes(remoteFile); long currentSize = fileAttr.Size; if (currentSize == lastSize) { stableCount++; if (stableCount >= 2) { return true; } } else { stableCount = 0; lastSize = currentSize; } System.Threading.Thread.Sleep(checkIntervalMs); } return false; }
调用的时候,先判断这个方法返回true,再执行下载操作就行。
方案2:利用临时文件命名规则
很多客户端上传文件时,会先传一个带临时后缀的文件(比如file.txt.tmp、file.txt.part),上传完成后再重命名为正式文件名。这种情况下,你只需要只下载正式命名的文件,忽略带临时后缀的文件就行。
如果是你自己控制上传端,那可以约定好临时后缀;如果是第三方客户端,你可以先观察一下他们的上传规律,再针对性处理。
方案3:检查文件的修改时间
和大小判断逻辑类似,上传中的文件修改时间会频繁变动。我们可以间隔获取文件的LastWriteTime,如果连续两次一致,说明文件没有被写入,上传完成。
示例代码片段:
var firstAttr = sftpClient.GetAttributes(remoteFile); System.Threading.Thread.Sleep(2000); var secondAttr = sftpClient.GetAttributes(remoteFile); if (firstAttr.LastWriteTime == secondAttr.LastWriteTime) { // 文件已稳定,可以下载 }
备选方案:捕获下载异常兜底
如果上面的方法都不适用,那可以在下载时捕获Renci的SftpException,根据异常信息判断是否是文件被占用的情况,然后提示用户重试。不过这个方法依赖服务器返回的异常信息,不同服务器可能不一样,属于兜底方案。
示例代码:
try { using (var localFile = File.Create(localFilePath)) { sftpClient.DownloadFile(remoteFilePath, localFile); } } catch (SftpException ex) { // 这里的异常信息需要根据你的服务器返回调整 if (ex.Message.IndexOf("locked", StringComparison.OrdinalIgnoreCase) >= 0 || ex.Message.IndexOf("in use", StringComparison.OrdinalIgnoreCase) >= 0) { Console.WriteLine("文件正在上传中,请稍后再试!"); } else { // 其他异常正常抛出 throw; } }
注意事项
- 方案1和3的间隔时间不要设太短,避免因为网络延迟误判;
- 如果服务器支持文件锁定或者能执行shell命令(比如Linux的
lsof),也可以尝试远程执行命令判断文件是否被占用,但这种方法局限性大,需要服务器开放shell权限,不推荐作为首选。
内容的提问来源于stack exchange,提问作者Mohit
相关产品推荐
相关产品推荐

