Reputation: 11975
I am not sure if this is the reason why its throwing error. But for me the test where I perform the File.Replace
with files residing in different directories failed. Just want to know if this is the case with others too.
[TestMethod]
public void TestFileReplaceDifferentDirectory()
{
string FileToReplace = @"c:\tools\file2.txt";
string FileToDelete = @"D:\DropFolder\file0.txt";
string strToWrite;
using (var wtr = File.CreateText(FileToDelete))
{
long ticks = DateTime.Now.Ticks;
strToWrite = string.Join(",", ticks, ticks, ticks);
wtr.WriteLine(strToWrite);
wtr.Flush();
wtr.Close();
}
string BackupFileName = Path.Combine(
Path.GetDirectoryName(FileToReplace),
string.Format("{0}_{1}{2}",
Path.GetFileNameWithoutExtension(FileToReplace),
DateTime.Now.Ticks,
Path.GetExtension(FileToReplace))
);
File.Replace(FileToDelete, FileToReplace, BackupFileName, false);
using (StreamReader rdr = new StreamReader(FileToReplace))
{
string line = rdr.ReadLine();
Assert.AreEqual(strToWrite, line);
}
}
[TestMethod]
public void TestFileReplaceSameDirectory()
{
string FileToReplace = @"c:\tools\file2.txt";
string FileToDelete = @"c:\tools\file0.txt";
string strToWrite;
using (var wtr = File.CreateText(FileToDelete))
{
long ticks = DateTime.Now.Ticks;
strToWrite = string.Join(",", ticks, ticks, ticks);
wtr.WriteLine(strToWrite);
wtr.Flush();
wtr.Close();
}
string BackupFileName = Path.Combine(
Path.GetDirectoryName(FileToReplace),
string.Format("{0}_{1}{2}",
Path.GetFileNameWithoutExtension(FileToReplace),
DateTime.Now.Ticks,
Path.GetExtension(FileToReplace))
);
File.Replace(FileToDelete, FileToReplace, BackupFileName, false);
using (StreamReader rdr = new StreamReader(FileToReplace))
{
string line = rdr.ReadLine();
Assert.AreEqual(strToWrite, line);
}
}
I was trying to write to a temporary file (using Path.GetTempFileName()
) and replace a file in D:\DropFolder
. It wasn't happening; it threw an System.IO.Exception
So does this mean my only option is to create a kind of temporary file in the same directory as that of FileToReplace
and carry out this task?
Upvotes: 0
Views: 193
Reputation: 941455
This is by design. The point of using File.Replace() is to be able to replace a file that's locked by another process. Very important if you have just one shot at saving precious data, common at machine shutdown or unexpected program termination. Needless to say, that does takes a trick or two since Windows is adamant about stopping you from overwriting a locked file.
It is possible at all because the operating system only puts a lock on the file data but not on the directory entry for a file. In other words, it is valid to rename the file, even though it is locked. The underlying system call is the same as File.Move().
Which operates two distinct ways, depending on the destFileName. If the destination path is on the same drive, the file system merely has to move the directory entry. Very fast and trouble-free. But that cannot work if it is not on the same drive, that requires moving the file data as well. Which is of course slow and not possible at all in a scenario where the file data is locked.
It is therefore imperative that the destinationBackupFileName argument you pass to File.Replace() is a path that's on the same drive as sourceFileName. Not doing this causes the exception when the move fails. Not otherwise hard to do in general, boilerplate is to make the backup filename simply the same as the source filename with, say, ".bak" appended to the path.
Upvotes: 1