Overwriting an existing file in C# I just found out about the existence of this forum and it's exactly what I needed. I just asked this question on Stack Overflow and after reading the answers I came up with a code (not the one I posted there but the one I'm posting here).

First, this is my messed up code:

string tempFile = Path.GetTempFileName();

using (Stream tempFileStream = File.Open(tempFile, FileMode.Truncate))
{
    SafeXmlSerializer xmlFormatter = new SafeXmlSerializer(typeof(Project));
    xmlFormatter.Serialize(tempFileStream, Project);
}

if (File.Exists(fileName)) File.Delete(fileName);
File.Move(tempFile, fileName);
if (File.Exists(tempFile)) File.Delete(tempFile);


When saving to an existing file that is in my Dropbox, it will, sometimes, delete the original file and fail to move the temporary file to the original location in File.Move(tempFile, fileName);. So here is my new code that I think it should never, unless the OS became self-conscious and evil, delete the original file without saving the new one. The worst it can happens is that the original will be renamed and will stay like that and I will have to let the user know (see the MessageBox at the bottom):

private string GetTempFileName(string dir)
{
    string name = null;
    int attempts = 0;
    do
    {
        name = "temp_" + Player.Math.RandomDigits(10) + ".hsp";
        attempts++;
        if (attempts &gt; 10) throw new Exception("Could not create temporary file.");
    }
    while (File.Exists(Path.Combine(dir, name)));

    return name;
}

private void TryToDelete(string path)
{
    try { File.Delete(path); }
    catch { }
}

private void SaveProject(string fileName)
{
    bool originalRenamed = false;
    string tempNewFile = null;
    string oldFileTempName = null;
    Exception exception = null;

    try
    {
        tempNewFile = GetTempFileName(Path.GetDirectoryName(fileName));

        using (Stream tempNewFileStream = File.Open(tempNewFile, FileMode.CreateNew))
        {
            SafeXmlSerializer xmlFormatter = new SafeXmlSerializer(typeof(Project));
            xmlFormatter.Serialize(tempNewFileStream, Project);
        }

        if (File.Exists(fileName))
        {
            oldFileTempName = GetTempFileName(Path.GetDirectoryName(fileName));
            File.Move(fileName, oldFileTempName);
            originalRenamed = true;
        }

        File.Move(tempNewFile, fileName);
        originalRenamed = false;

        CurrentProjectPath = fileName;
    }
    catch (Exception ex)
    {
        exception = ex;
    }
    finally
    {
        if (tempNewFile != null) TryToDelete(tempNewFile);

        if (originalRenamed)
        {
            try
            {
                File.Move(oldFileTempName, fileName);
                originalRenamed = false;
            }
            catch { }
        }

        if (exception != null) MessageBox.Show(exception.Message);

        if (originalRenamed)
        {
            MessageBox.Show("'" + fileName + "'" +
                " have been corrupted or deleted in this operation.\n" +
                "A backup copy have been created at '" + oldFileTempName + "'");
        }
        else if (oldFileTempName != null) TryToDelete(oldFileTempName);
    }
}


Player.Math.RandomDigits is just a function that returns a string with random digits. Do you think my code is safe as I think it is or am I missing something? It's hard for me to test every possible exception.
Using File.Replace() still seems the best option to me. As you mentioned on SO, the following might give a problem:


  If the sourceFileName and
  destinationFileName are on different
  volumes, this method will raise an
  exception. If the
  destinationBackupFileName is on a
  different volume from the source file,
  the backup file will be deleted.


To prevent this exception from being thrown, can't you first check whether you can serialize the temp file directly to the desired volume? If this isn't possible, further processing will fail as well, so you can already show a message that the volume isn't writeable.

Afterwards, call the Replace function, creating a backup file. When it fails, handle appropriately and check in which state your files are, indicate to the user when something is 'corrupt' (so point to the backup file). In the finally check whether the backup file exists and remove.