我构建了一个控制台应用程序,该应用程序监视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)) { }
}
}
}
我要在OnCreated
方法中执行的操作是检查并等待,直到文件创建完成,然后将文件复制到另一个目标位置。我似乎不知道我在WaitForFile(file)
行中所做的工作-如果我注释掉该行并且文件创建是即时的,则文件将按预期进行复制。如果我使用WaitForFile
行,则不会发生任何事情。我从SO的其他帖子中采用了IsFileLocked
和WaitForFile
方法,但是显然我没有正确实现它们。
我已经注意到了这个Powershell版本Copy File On Creation (once complete),但我不确定这里的答案是否可以将我指向正确的方向b / c我对PS的了解甚至不如对C#的了解。
编辑#1:在接受答案之前,我应该进行更长时间的测试-我认为我们已经关闭了,但是在程序运行约一分钟后,在程序崩溃之前出现了以下错误:
未处理的异常。 System.IO.IOException:进程无法访问 文件 'C:\ Users \ me \ Dropbox \ test1.log' 因为它正在被另一个进程使用。在 System.IO.FileSystem.CopyFile(String sourceFullPath,String destFullPath,布尔覆盖) Folderwatch.Program.OnCreated(对象源,FileSystemEventArgs e)在 C:\ Users \ me \ OneDrive- Development \ Source \ repos \ FolderWatchCG \ FolderWatchCG \ Program.cs:line 61在System.Threading.Tasks.Task。<> c.b__139_1(Object 州) System.Threading.QueueUserWorkItemCallbackDefaultContext.Execute()
在System.Threading.ThreadPoolWorkQueue.Dispatch()处 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
任何对此的建议将不胜感激。当我进一步分析这些文件夹中的文件时,其中一些是实时写入的日志文件,因此可能是在实际完成写入之前将其写入了几个小时。我想知道NotifyFilter
之一是否在这里起作用?
答案 0 :(得分:3)
WaitForFile()
方法中存在一个错误,即它当前正在等待文件 not 锁定时(反之亦然)。除此之外,您还需要一种方法来确认文件确实存在。一种简单的实现方法是将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;
}
只要文件存在并且无法访问,它将一直等待。
然后,您可以按以下方式使用它:
bool fileAvailable = WaitForFile(file);
if (fileAvailable)
{
File.Copy(sourceFile, destFile, true);
}
这种方法的问题是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;
}
然后在OnCreated
内等待,像这样:
private async static void OnCreated(object source, FileSystemEventArgs e)
{
// ...
bool fileAvailable = await WaitForFile(file);
if (fileAvailable)
{
File.Copy(sourceFile, destFile, true);
}
}