The following .NET 8 targetted code (formatted as xunit test) fails on my machine (Windows 11), typically j
is something between 50 and 100.
[Fact]
void FileMoveException()
{
var sourceFilePath = Path.GetTempFileName();
using var delete1 = Disposable.Create(() => File.Delete(sourceFilePath)); // can be removed, just helps clean up %TEMP% after the unit test
var destFilePath = Path.GetTempFileName();
using var delete2 = Disposable.Create(() => File.Delete(destFilePath)); // can be removed, just helps clean up %TEMP% after the unit test
for(int j = 0; j < 10000; j++)
{
//try
{
File.WriteAllText(sourceFilePath, "test");
// File.Delete(destFilePath); // works if File.Delete is executed
File.Move(sourceFilePath, destFilePath, true);
}
// catch (Exception e) when (!Debugger.IsAttached)
// {
// Console.WriteLine($"Failed j={j} {sourceFilePath} {destFilePath} {e}");
// _testOutputHelper.WriteLine($"Failed j={j} {sourceFilePath} {destFilePath} {e}");
// throw;
// }
}
}
Local file system (%TEMP%) on an SSD drive. Error occurs non-deterministic (different j
).
Windows defender is active but IMHO should not change FileSystem behaviour (aside from performance of course).
If I File.Delete
(see code comment) before File.Move
everything seems to work fine (tested with 100000 iterations). If I just add some Thread.Sleep(1)
or Thread.Sleep(10)
it does not work (same issue, even similar iteration count).
From my experiments it's not related to the source file. Seems like the destination file is (still) blocked by a previous iteration.
Using win32 api function MoveFileEx
with WriteThrough
option did not help, either.
I thought File.Move would be an atomic operation (operating in same local folder) or at least function should not lock the file beyond runtime.
Edit: Occurs on different machines (different hardware etc).
Edit2: Error is System.UnauthorizedAccessException: Access to the path is denied.
Edit3: Another test without %TEMP% and without Disposable
helper and with a variant to create the file:
[Fact]
void FileMoveException2()
{
var sourceFilePath = @"c:\tmp2\source.txt";
var destFilePath = @"c:\tmp2\target.txt";
for (int j = 0; j < 10000; j++)
{
try
{
using (var x = new FileStream(sourceFilePath, new FileStreamOptions()
{
Options = FileOptions.WriteThrough,
Access = FileAccess.Write,
Mode = FileMode.OpenOrCreate,
Share = FileShare.None
}))
{
x.WriteByte(42);
}
File.Move(sourceFilePath, destFilePath, true);
}
catch (Exception e) when (!Debugger.IsAttached)
{
Console.WriteLine($"Failed j={j} {sourceFilePath} {destFilePath} {e}");
_testOutputHelper.WriteLine($"Failed j={j} {sourceFilePath} {destFilePath} {e}");
throw;
}
}
}