Mimic File.Move, если место назначения уже существует

Из документации File.Move:

Обратите внимание, что если вы попытаетесь заменить файл, переместив файл с тем же именем в этот каталог, вы получите IOException. Вы не можете использовать метод Move, чтобы перезаписать существующий файл.

Короче говоря, вы не можете перезаписать на Move так, чтобы облегчить перезапись на Move, я имитирую поведение, выполняя File.Copy с последующим File.Delete, Что-то вроде:

if (File.Exists(dstFileName))
{
    // System.IO.File.Move cannot be used to overwrite existing files, so we're going
    // to simulate that behavior with a Copy & Delete.
    File.Copy(procContext.FileName, dstFileName);
    File.Delete(procContext.FileName);
}
else
    File.Move(procContext.FileName, dstFileName);

У меня такой вопрос: есть ли ситуации, которые мне нужно защищать, которые могут привести к удалению исходного файла без его успешного копирования?

Насколько я понимаю из чтения документации, так как File.Copy не возвращает ничего, что должно выдать исключение в любом случае, если это не удалось. Кто-нибудь сталкивался с ситуациями, когда это не так?

5 ответов

Решение

Я предлагаю вам сначала проверить, существует ли целевой файл, и если да, удалить его. Затем выполните обычную операцию перемещения.

Поскольку эта последовательность не является атомарной, в случае, если место назначения существует, вы можете переименовать его вместо удаления, чтобы не потерять его в случае неудачного перемещения.

Правильный способ сделать это будет позвонить

File.Replace(source, destination, copy)

Это делает трюк для меня

Трудно смоделировать атомарную операцию, если операционная система не дает хороших атомарных операций. Move атомарна в некоторых, но не во всех файловых системах, но не во время перемещения диска на диск.

В случае того же диска, Delete + Move это несколько элегантно (быстро и безопасно), так как на самом деле не заполняет данные. Вы могли бы расширить его до

try
{
    Move(dest, tmp);
    Move(src, dest);
    Delete(tmp);
}
catch
{
    try
    {
        Move(tmp, dest);
    }
    catch
    {
    }
    throw;
}

(Это снижает вероятность того, что вы потеряете файл назначения, если, например, у вас нет прав, необходимых для завершения перемещения.)

В сценарии, когда вы не знаете, что это тот же диск, ваше решение достаточно безопасно и достаточно просто. Тем не менее, он копирует данные даже на одном диске, что увеличивает вероятность сбоя питания.

Это безопасно. File.Copy либо удастся полностью, либо выкинет. Конечно, удаление может завершиться неудачей, оставив исходный файл как мусор.

Если ваш компьютер выходит из строя, тем не менее, нет никакой гарантии, что операция копирования еще больше укрепила данные. Вы можете потерять данные в этом случае.

Во время нормальной работы это безопасно.

Проверьте, существует ли файл "Target". Если нет, скопируйте ваш файл.

Если да: переместите "Target" в временный каталог, где вы можете быть уверены, что этот шаг будет успешным. Вы можете создать subdir в Temp с именем auf UUID. Затем скопируйте ваш файл.

Другие вопросы по тегам