File.Move не работает - файл уже существует

86

У меня есть папка:

c: \ test

Я пробую этот код:

File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test");

Я получаю исключение:

Файл уже существует

Выходной каталог определенно существует, и входной файл есть.

Джек Када
источник
2
Если входной файл уже находится в выходном каталоге, значит, файл уже существует, что объясняет исключение. Вам необходимо указать, что вы хотите, чтобы исходный файл был перезаписан новым.
Коди Грей
9
Похоже, ошибка говорит вам, что именно не так.
Джош
@Josh Нет. Похоже, Windows имеет поведение файловой системы, отличное от POSIX, что делает невозможным определение простого переносимого шаблона / процедуры обновления транзакционного файла.
binki
@binki POSIX не имеет значения (вы ссылаетесь на атомные операции?), NTFS делает поддержку реальные транзакционные операции, как в откате-и-получить по-оригинал-файл-контент-обратно. Как ответили другие, Win32 делает позволяет двигаться с заменить. Это .NET File.Move, который не обеспечивает такой функциональности. Вы можете получить как Move с заменой, так и транзакционные операции с такими библиотеками, как AlphaFS
Панайотис Канавос
2
@binki в любом случае поведение хорошо определено в разных файловых системах , что бы ни говорили обсуждения на форумах. Причина, по которой File.Move не вызывает методы Ex или Transcted, заключается в том, что FAT, который нельзя игнорировать, поскольку он все еще используется картами памяти, не является атомарным и ведет себя иначе. Переименование не является операцией с метаданными и требует фактического перемещения данных. И забудьте о транзакциях и копировании при записи. Не
лучшее

Ответы:

62

Вам нужно переместить его в другой файл (а не в папку), это также можно использовать для переименования.

Переехать:

File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");

Переименовать:

File.Move(@"c:\test\SomeFile.txt", @"c:\test\SomeFile2.txt");

Причина, по которой в вашем примере написано «Файл уже существует», заключается в том, что он C:\test\Testпытается создать файл Testбез расширения, но не может этого сделать, поскольку папка с таким именем уже существует.

Ли
источник
138

Что вам нужно:

if (!File.Exists(@"c:\test\Test\SomeFile.txt")) {
    File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");
}

или

if (File.Exists(@"c:\test\Test\SomeFile.txt")) {
    File.Delete(@"c:\test\Test\SomeFile.txt");
}
File.Move(@"c:\test\SomeFile.txt", @"c:\test\Test\SomeFile.txt");

Это либо:

  • Если файл не существует в месте назначения, успешно переместите файл, или;
  • Если файл действительно существует в месте назначения, удалите его, а затем переместите файл.

Изменить: я должен уточнить свой ответ, хотя он получил наибольшее количество голосов! Второй параметр File.Move должен быть файл назначения - не папка. Вы указываете второй параметр как папку назначения, а не имя файла назначения - это то, что требует File.Move. Итак, ваш второй параметр должен быть c:\test\Test\SomeFile.txt.

Джейми Ховарт
источник
Разумеется, не нужно проверять, нет ли файла, потому что он проверяет, а файла нет. Исключение вызвано тем, что имя файла не добавляется в папку назначения при попытке переместить его в другую папку.
Хади Эскандари
3
Если ваше приложение является многопоточным (или с вашими файлами работают другие процессы), вы можете получить такое же исключение, даже используя код «if (Exists) Delete». Поскольку еще есть промежуток времени, когда другой поток / процесс мог бы вернуть файл после удаления, вы делаете свой ход, а затем все равно получаете исключение. Стоит просто иметь в виду :-)
bytedev
11
Этот ответ по-прежнему актуален для большинства людей, которые ищут в Google после попытки перезаписать существующий файл. У большинства людей в этой затруднительной ситуации нет проблем с синтаксисом / типом, как у OP.
WEFX
1
@ v.oddou интересно, что если файл не существует, File.Delete действительно работает правильно и ничего не делает. Если вместо этого какой-либо из каталогов в пути не существует, вы получите исключение DirectoryNotFoundException.
Брэндон Баркли
2
@JirkaHanika вы можете изменить if (File.Exists) на while (File.Exists).
Брэндон Баркли
38

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

string source = @"c:\test\SomeFile.txt";
string destination = @"c:\test\test\SomeFile.txt";

try
{
    File.Copy(source, destination, true);
    File.Delete(source);
}
catch
{
    //some error handling
}
Митчелл
источник
4
Это нормально для небольших файлов (и не требует атомарного перемещения), но для больших файлов или случаев, когда вам нужно быть уверенным, что у вас не будут дубликаты, это проблематично.
River Satya
Почему ты предпочитаешь File.Copy , File.Deleteбольше File.Move?
Джон Пьетрар
6
File.Move не имеет опции перезаписи.
Митчелл
1
В зависимости от вашего варианта использования это может вызвать проблемы. «Move» - реальное событие в наблюдателе файловой системы. Что-то, перечисленное в событиях файловой системы, получит событие удаления и создания вместо события перемещения. Это также изменит идентификатор базовой файловой системы.
Эндрю Рондо
1
Не будет ли это менее эффективным для больших файлов? Если источник и место назначения находятся на одном физическом томе, вы создаете вторую копию без причины, а затем удаляете оригинал, тогда как File.Move () не выполняет дополнительную работу, если источник и место назначения находятся на одном томе.
Брэд Вестнесс
18

Вы можете сделать P / Invoke для MoveFileEx()- передать 11 для flags( MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
static extern bool MoveFileEx(string existingFileName, string newFileName, int flags);

Или вы можете просто позвонить

Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(existingFileName, newFileName, true);

после добавления Microsoft.VisualBasic в качестве ссылки.

Mheyman
источник
Совершенно нормально, если приложение работает только в Windows. Вероятно, это хороший ответ для большинства людей, которые хотят попробовать P / Invoke.
Тодд
9

Если файл действительно существует, и вы хотите его заменить, используйте следующий код:

string file = "c:\test\SomeFile.txt"
string moveTo = "c:\test\test\SomeFile.txt"

if (File.Exists(moveTo))
{
    File.Delete(moveTo);
}

File.Move(file, moveTo);
Павел Чапски
источник
4

Согласно документам для File.Move нет параметра «перезаписать, если существует». Вы пытались указать папку назначения , но вы должны указать полную спецификацию файла.

Прочитав документы еще раз («предоставление возможности указать новое имя файла»), я думаю , что добавление обратной косой черты к спецификации целевой папки может сработать.

Эккехард, Хорнер
источник
И в документации упоминается, что если вы попытаетесь заменить файл, переместив файл с тем же именем в этот каталог, будет выброшено исключение IOException. Для этого Move(String, String, Boolean)вместо этого позвоните . но это кажется ошибкой?
Кевин Шарнхорст,
@KevinScharnhorst Это ответ 2011 года. В документации теперь включена поддержка .Net Core 3.0 для перемещения с перезаписью.
Тодд
4

1) В C # в .Net Core 3.0 и выше теперь есть третий логический параметр:

см. https://docs.microsoft.com/en-us/dotnet/api/system.io.file.move?view=netcore-3.1

In .NET Core 3.0 and later versions, you can call Move(String, String, Boolean) setting the parameter overwrite to true, which will replace the file if it exists.

2) Для всех других версий .Net https://stackoverflow.com/a/42224803/887092 - лучший ответ. Скопируйте с перезаписью, затем удалите исходный файл. Это лучше, потому что это атомарная операция. (Я попытался обновить MS Docs этим)

Тодд
источник
2

Попробуй Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). Последний параметр - переключатель перезаписи, которого System.IO.File.Moveнет.

отметка
источник
2
Здесь уже есть другой ответ, похожий на тот же самый stackoverflow.com/a/42224803/1236734
JG в SD
Это ответ, который предполагает то же самое: stackoverflow.com/a/38372760/887092 , а не stackoverflow.com/a/42224803/1236734
Тодд
1

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

string newFileLocation = @"c:\test\Test\SomeFile.txt";

while (File.Exists(newFileLocation)) {
    newFileLocation = newFileLocation.Split('.')[0] + "_copy." + newFileLocation.Split('.')[1];
}
File.Move(@"c:\test\SomeFile.txt", newFileLocation);

Это предполагает единственный "." в имени файла стоит перед расширением. Он разбивает файл на две части перед расширением, прикрепляет «_copy». между. Это позволяет вам переместить файл, но создает копию, если файл уже существует, или копия копии уже существует, или копия копии копии существует ...;)

Рыскание
источник