Stp*_*111 3 c# filesystemwatcher
我构建了一个控制台应用程序,用于监视 Windows 2019 Server 上的一组文件夹,并使用相同的文件名将任何新创建的 .txt 文件复制到另一个文件夹。到目前为止,它可以实现基本功能。现在我必须处理这样一个事实:大多数时候,这些文件很大,需要几分钟才能完成创建。我已经浏览了几篇 SO 帖子,并拼凑了以下代码来尝试完成此任务:
using System;
using System.IO;
namespace Folderwatch
{
class Program
{
static void Main(string[] args)
{
string sourcePath = @"C:\Users\me\Documents\SomeFolder";
FileSystemWatcher watcher = new FileSystemWatcher(sourcePath);
watcher.EnableRaisingEvents = true;
watcher.IncludeSubdirectories = true;
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Created += new FileSystemEventHandler(OnCreated);
}
// Define the event handlers.
private static void OnCreated(object source, FileSystemEventArgs e)
{
// Specify what is done when a file is created.
FileInfo file = new FileInfo(e.FullPath);
string wctPath = e.FullPath;
string wctName = e.Name;
string createdFile = Path.GetFileName(wctName);
string destPath = @"C:\Users\SomeOtherFolder";
string sourceFile = wctPath;
string destFile = Path.Combine(destPath, createdFile);
WaitForFile(file);
File.Copy(sourceFile, destFile, true);
}
public static bool IsFileLocked(FileInfo file)
{
try
{
using (FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
{
stream.Close();
}
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
//file is not locked
return false;
}
public static void WaitForFile(FileInfo filename)
{
//This will lock the execution until the file is ready
//TODO: Add some logic to make it async and cancelable
while (!IsFileLocked(filename)) { }
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在该方法中尝试执行的操作OnCreated是检查并等待文件创建完成,然后将文件复制到另一个目标。我似乎不知道我在用该WaitForFile(file)行做什么 - 如果我注释掉该行并且文件创建是即时的,文件将按预期复制。如果我使用这WaitForFile条线,就不会发生任何事情。我从其他帖子中获取了IsFileLocked和方法,但显然我没有正确实现它们。WaitForFile
我注意到这个 Powershell 版本创建时复制文件(一旦完成),我不确定这里的答案是否可以为我指明正确的方向,因为我对 PS 的了解甚至不如对 C# 的了解。
编辑#1:在接受答案之前我应该测试更长时间 - 我认为我们已经接近了,但是在程序运行大约一分钟后,我在程序崩溃之前收到以下错误:
未处理的异常。System.IO.IOException:进程无法访问文件“C:\Users\me\Dropbox\test1.log”,因为它正在被另一个进程使用。在System.IO.FileSystem.CopyFile(字符串sourceFullPath,字符串destFullPath,布尔覆盖)在Folderwatch.Program.OnCreated(对象源,FileSystemEventArgs e)在C:\Users\me\OneDrive - Development\Source\repos\FolderWatchCG\FolderWatchCG \Program.cs:第 61 行位于 System.Threading.Tasks.Task。<>c.b__139_1(对象状态)位于 System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
位于 System.Threading.ThreadPoolWorkQueue.Dispatch() 位于 System.Threading。 _ThreadPoolWaitCallback.PerformWaitCallback()
任何对此的建议将不胜感激。当我进一步分析这些文件夹中的文件时,其中一些是实时写入的日志文件,因此文件可能在实际完成之前就已经写入了几个小时。我想知道其中之一是否NotifyFilter会在这里发挥作用?
该方法有一个错误WaitForFile(),即它当前在文件未锁定时等待(而不是相反)。除此之外,您还需要一种方法来确认该文件确实存在。实现这一目标的一个简单方法是将WaitForFile()方法更改为如下所示:
public static bool WaitForFile(FileInfo file)
{
while (IsFileLocked(file))
{
// The file is inaccessible. Let's check if it exists.
if (!file.Exists) return false;
}
// The file is accessible now.
return true;
}
Run Code Online (Sandbox Code Playgroud)
只要文件存在且无法访问,这就会一直等待。
然后,您可以按如下方式使用它:
bool fileAvailable = WaitForFile(file);
if (fileAvailable)
{
File.Copy(sourceFile, destFile, true);
}
Run Code Online (Sandbox Code Playgroud)
但这种方法的问题在于循环使while线程保持繁忙,这 a) 消耗了大量的 CPU 资源,b) 阻止程序处理其他文件,直到它完成等待该文件。因此,最好在每次检查之间使用异步等待。
将方法更改WaitForFile为:
public static async Task<bool> WaitForFile(FileInfo file)
{
while (IsFileLocked(file))
{
// The file is inaccessible. Let's check if it exists.
if (!file.Exists) return false;
await Task.Delay(100);
}
// The file is accessible now.
return true;
}
Run Code Online (Sandbox Code Playgroud)
OnCreated然后,像这样在里面等待:
private async static void OnCreated(object source, FileSystemEventArgs e)
{
// ...
bool fileAvailable = await WaitForFile(file);
if (fileAvailable)
{
File.Copy(sourceFile, destFile, true);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2533 次 |
| 最近记录: |