C# 仅当存在匹配文件时才移动文件
我有一个需要两个文件来处理数据的应用程序。包含实际数据的zip文件,然后是说明如何处理所述数据的控制文件 这些文件通过sftp下载到暂存目录。一旦zip文件完成,我需要检查控制文件是否也在那里。它们只共享一个命名前缀(例如100001_ABCDEF_123456.zip与100001_ABCDEF_control_file.ctl配对) 我试图找到一种方法,等待zip文件完成下载,然后动态移动文件,同时保持目录结构,因为这对于处理的下一步很重要 目前我正在等待sftp工作人员完成,然后打电话给robocopy移动所有东西。我希望有一个更完善的方法 我尝试了几种方法,但得到了相同的结果。文件下载但从未移动。由于某些原因,我无法正确进行比较 我曾尝试使用FileSystemWatcher来查找从filepart重命名为zip,但它似乎错过了几次下载,并且由于某种原因,当我到达我的foreach以搜索目录中的控制文件时,该函数将终止。 下面是FileSystemWatcher事件,我为创建和更改调用此事件。 下面是filesystemwatcher的设置C# 仅当存在匹配文件时才移动文件,c#,file-io,sftp,C#,File Io,Sftp,我有一个需要两个文件来处理数据的应用程序。包含实际数据的zip文件,然后是说明如何处理所述数据的控制文件 这些文件通过sftp下载到暂存目录。一旦zip文件完成,我需要检查控制文件是否也在那里。它们只共享一个命名前缀(例如100001_ABCDEF_123456.zip与100001_ABCDEF_control_file.ctl配对) 我试图找到一种方法,等待zip文件完成下载,然后动态移动文件,同时保持目录结构,因为这对于处理的下一步很重要 目前我正在等待sftp工作人员完成,然后打电话给r
watcher.Path = @"C:\Sync\";
watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
watcher.Filter = "*.zip";
watcher.NotifyFilter = NotifyFilters.Attributes |
NotifyFilters.CreationTime |
NotifyFilters.FileName |
NotifyFilters.LastAccess |
NotifyFilters.LastWrite |
NotifyFilters.Size |
NotifyFilters.Security |
NotifyFilters.CreationTime |
NotifyFilters.DirectoryName;
watcher.Created += Watcher_Changed;
watcher.Changed += Watcher_Changed;
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
var dir = new DirectoryInfo(e.FullPath.Substring(0, e.FullPath.Length - e.Name.Length));
var files = dir.GetFiles();
FileInfo zipFile = new FileInfo(e.FullPath);
foreach (FileInfo file in files)
{
MessageBox.Show(file.Extension);
if (file.Extension == "ctl" && file.Name.StartsWith(e.Name.Substring(0, (e.Name.Length - 14))))
{
file.CopyTo(@"C:\inp\");
zipFile.CopyTo(@"C:\inp\");
}
}
}
被改变的观察者将被要求做各种各样的事情,而不是每一次你都想对它做出反应 在事件处理程序中,您应该做的第一件事是尝试以独占方式打开zipFile。如果您做不到,请忽略此事件并等待另一个事件。如果这是FTP服务器,则每次将新数据块写入磁盘时,您都会收到一个更改的事件。您还可以将某些内容置于“重试”状态排队或使用其他机制检查文件是否在以后可用。我在我们的系统中有类似的需求,我们在注意到第一次更改后每5秒尝试一次。只有在我们能够以独占方式打开文件进行写入时,我们才允许它进入下一步 我将加强您对文件名外观的假设。您将搜索限制为*.zip,但不要仅依赖于该目标目录中存在的.zip文件。请验证您正在对文件名进行的解析是否没有遇到意外值。您可能还想检查dir.Exists()调用dir.GetFiles()之前,可能会引发异常
关于丢失的事件,请参阅缓冲区溢出的这个好答案:众所周知,FileSystemWatcher类的正确使用非常棘手,因为您将为正在写入、移动或复制的单个文件获得多个事件,@WillStoltenberg在他的文章中也提到了这一点 我发现,只设置一个周期性运行的任务(例如每30秒一次)要容易得多。对于您的问题,您可以轻松地执行以下操作。请注意,使用计时器而不是
任务的类似实现。延迟,可能更可取
public class MyPeriodicWatcher
{
private readonly string _watchPath;
private readonly string _searchMask;
private readonly Func<string, string> _commonPrefixFetcher;
private readonly Action<FileInfo, FileInfo> _pairProcessor;
private readonly TimeSpan _checkInterval;
private readonly CancellationToken _cancelToken;
public MyPeriodicWatcher(
string watchPath,
string searchMask,
Func<string, string> commonPrefixFetcher,
Action<FileInfo, FileInfo> pairProcessor,
TimeSpan checkInterval,
CancellationToken cancelToken)
{
_watchPath = watchPath;
_searchMask = string.IsNullOrWhiteSpace(searchMask) ? "*.zip" : searchMask;
_pairProcessor = pairProcessor;
_commonPrefixFetcher = commonPrefixFetcher;
_cancelToken = cancelToken;
_checkInterval = checkInterval;
}
public Task Watch()
{
while (!_cancelToken.IsCancellationRequested)
{
try
{
foreach (var file in Directory.EnumerateFiles(_watchPath, _searchMask))
{
var pairPrefix = _commonPrefixFetcher(file);
if (!string.IsNullOrWhiteSpace(pairPrefix))
{
var match = Directory.EnumerateFiles(_watchPath, pairPrefix + "*.ctl").FirstOrDefault();
if (!string.IsNullOrEmpty(match) && !_cancelToken.IsCancellationRequested)
_pairProcessor(
new FileInfo(Path.Combine(_watchPath, file)),
new FileInfo(Path.Combine(_watchPath, match)));
}
if (_cancelToken.IsCancellationRequested)
break;
}
if (_cancelToken.IsCancellationRequested)
break;
Task.Delay(_checkInterval, _cancelToken).Wait().ConfigureAwait(false);
}
catch (OperationCanceledException)
{
break;
}
}
}
}
公共类MyPeriodicWatcher
{
私有只读字符串\u监视路径;
私有只读字符串_searchMask;
专用只读函数\u commonPrefixFetcher;
专用只读操作处理器;
私有只读时间间隔_checkInterval;
私有只读取消令牌\u取消令牌;
公共MyPeriodicWatcher(
字符串监视路径,
字符串搜索掩码,
Func CommonPrefitcher,
动作配对处理器,
时间跨度检查间隔,
取消令牌(取消令牌)
{
_监视路径=监视路径;
_searchMask=string.IsNullOrWhiteSpace(searchMask)?“*.zip”:searchMask;
_成对处理器=成对处理器;
_commonPrefixFetcher=commonPrefixFetcher;
_cancelToken=cancelToken;
_检查间隔=检查间隔;
}
公共任务观察()
{
而(!\u cancelToken.IsCancellationRequested)
{
尝试
{
foreach(目录中的var文件。枚举文件(_watchPath,_searchMask))
{
var pairPrefix=_commonPrefixFetcher(文件);
如果(!string.IsNullOrWhiteSpace(pairPrefix))
{
var match=Directory.EnumerateFiles(_watchPath,pairPrefix+“*.ctl”).FirstOrDefault();
如果(!string.IsNullOrEmpty(match)&&&!\u cancelToken.IsCancellationRequested)
_成对处理器(
新文件信息(Path.Combine(_watchPath,file)),
新文件信息(Path.Combine(_watchPath,match));
}
如果(_cancelToken.IsCancellationRequested)
打破
}
如果(_cancelToken.IsCancellationRequested)
打破
Task.Delay(_checkInterval,_cancelToken).Wait().configurewait(false);
}
捕获(操作取消异常)
{
打破
}
}
}
}
您需要为其提供
- 监视的路径
- 第一个文件(即.*.zip)的搜索掩码
- 从zip文件名获取公共文件名前缀的函数委托
- 间歇
- 将执行移动并接收待处理/移动对的
FileInfo
的代理
- 以及用于完全取消监视的取消令牌
在您的pairProcessor
委托中,捕获IO异常,并检查共享冲突(这可能意味着写入文件尚未完成)。在您的监视程序中,即监视路径@“C:\Sync\”
您设置了watcher.IncludeSubdirectories=true;
。在文件处理中,您将文件移动到@“C:\Sync\inp\”
。这是观察者正在监视的子目录。Tha