private void OnCreated(object sender, FileSystemEventArgs e)
{
this.Invoke(new Action(
delegate ()
{
RichTextBoxExtensions.AppendText(richTextBox1, $"Created: {e.FullPath}", Color.GreenYellow);
RichTextBoxExtensions.AppendText(richTextBox1, $" On: {DateTime.Now}", Color.Yellow);
richTextBox1.AppendText(Environment.NewLine);
string folderName = savedGamesPath "\\Save Game " DateTime.Now.ToString("dddd, dd MMMM yyyy");
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
string destFile = Path.Combine(folderName, e.Name);
File.Copy(e.FullPath, destFile);
}));
}
I'm using filesystemwatcher and the problem is that the first time it's doing File.Copy it's fine but then it's doing it again and in the second time it's giving exception that it can't find the directory.
First, why it's doing it twice in a row ? and how to make that it will copy the file only once ?
CodePudding user response:
The test code that I made to replicate your issue suggests that the second OnCreate
event occurs when the Save Game
directory is created. AFAIK the simplest way to detect that is to try it as a DirectoryInfo
first:
private void onCreated(object sender, FileSystemEventArgs e)
{
if (Directory.Exists(e.FullPath))
{
var fiCopy = new FileInfo(e.FullPath);
richTextBox1.AppendText($"Created Directory: {e.FullPath}", Color.LightCoral, newLine: false);
richTextBox1.AppendText($" On: {fiCopy.CreationTime}", Color.Yellow);
return; // this is a directory, not a file.
}
Debug.Assert(string.Equals(Path.GetDirectoryName(e.FullPath), savedGamesPath), "Expecting none other");
var fiSrce = new FileInfo(e.FullPath);
string folderName = Path.Combine(
savedGamesPath,
$"Save Game {fiSrce.CreationTime.ToString("dddd, dd MMMM yyyy")}");
// Harmless if already exists
Directory.CreateDirectory(folderName);
string destFile = Path.Combine(folderName, e.Name);
File.Copy(e.FullPath, destFile);
Debug.Assert(
fiSrce.CreationTime.Equals(fiSrce.LastWriteTime),
"Expecting matching CreationTime"
);
var fiDest = new FileInfo(destFile);
Debug.Assert(
!fiSrce.CreationTime.Equals(fiDest.CreationTime),
"Expecting different CreationTime"
);
fiDest.CreationTime = fiSrce.CreationTime;
fiDest.LastWriteTime = fiSrce.LastWriteTime;
Debug.Assert(
fiSrce.CreationTime.Equals(fiDest.CreationTime),
"Expecting matching CreationTime"
);
richTextBox1.AppendText($"Created: {e.FullPath}", Color.GreenYellow, newLine: false);
richTextBox1.AppendText($" On: {fiSrce.CreationTime}", Color.Yellow);
}
If building in NET Core 6 the Invoke
won't be needed as long as the SynchronizingObject
property of the FSW is set to this
. In legacy NET Core 3.1 it may be necessary to Invoke
or preferably BeginInvoke
regardless.
The CreationTime properties were mentioned so I went ahead and made the original and the copy have matched times. It doesn't appear that these times were at play in the behavior you're describing, however.
MOCK
The way you have it now, your Save Game directory is based on calendar day only and it will be created just once even of new games are created like this test run with Games 1, 2 and 3.
In this sample, the FileSystemWatcher
is initialized in the MainForm
CTor. In Net Core 6, if the SynchronizingObject
property is set to this
it shouldn't be necessary to use Invoke
when calling RichTextBox
in the event handlers. This approach didn't seem to work for legacy .NET Core 3.1 in VS 2019. Judicious use of Invoke, or preferably BeginInvoke, may still be required.
public MainForm()
{
InitializeComponent();
savedGamesPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"StackOverflow",
"filewatcher_with_copy"
);
// Start with clean slate for test
Directory.Delete(savedGamesPath, recursive: true);
// ===============================
Directory.CreateDirectory(savedGamesPath);
_fileSystemWatcher = new FileSystemWatcher()
{
Path = savedGamesPath,
IncludeSubdirectories = false,
SynchronizingObject = this, // But it seems to complain if not Invoked "anyway"
};
_fileSystemWatcher.Created = onCreated;
_fileSystemWatcher.Changed = onChanged;
_fileSystemWatcher.Deleted = onDeleted;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private FileSystemWatcher _fileSystemWatcher;
private readonly string savedGamesPath;
private int _gameCount = 0;
private void buttonNewGame_Click(object sender, EventArgs e)
{
_gameCount ;
var gamePrimary = Path.Combine(savedGamesPath, $"Game{_gameCount}.game");
File.WriteAllText(gamePrimary, String.Empty);
}
AppendText Extension
static class Extensions
{
public static void AppendText(this RichTextBox richTextBox, string text, Color color, bool newLine = true)
{
var colorB4 = richTextBox.SelectionColor;
richTextBox.SelectionColor = color;
richTextBox.AppendText(text);
richTextBox.SelectionColor = colorB4;
if (newLine) richTextBox.AppendText(Environment.NewLine);
}
}