File.Move не працює - файл уже існує


86

У мене є папка:

c: \ test

Я пробую цей код:

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

Я отримую виняток:

Файл уже існує

Вихідний каталог безумовно існує, і вхідний файл є.


2
Якщо вхідний файл вже знаходиться у вихідному каталозі, то файл уже існує, пояснюючи тим самим виняток. Вам потрібно вказати, що ви хочете, щоб оригінальний файл був замінений новим.
Коді Грей

9
Здається, помилка повідомляє вам, що саме не так.
Джош

@Josh No. Здається, Windows має поведінку файлової системи не POSIX, що робить неможливим з’ясувати простий переносний шаблон / процедуру оновлення транзакційних файлів.
binki

@binki POSIX не має значення (ви маєте на увазі атомні операції?), NTFS дійсно підтримує реальні транзакційні операції, як у відкаті та отриманні оригінального файлу-вмісту-назад. Як відповіли інші, Win32 робить дозволяє рухатися з замінити. Я.NET. File.Move, який не забезпечує функціональність. Ви можете отримати як Move with replace, так і транзакційні операції з такими бібліотеками, як AlphaFS
Panagiotis Kanavos

2
@binki у будь-якому випадку поведінка чітко визначена в різних файлових системах , незалежно від того, що говорять дискусії на форумах. Причиною того, що File.Move не викликає методи Ex або Transacted, є те, що 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
Якщо ваш додаток є багатопотоковим (або на ваших файлах працюють інші процеси), ви все одно можете отримати той самий виняток, навіть використовуючи код "якщо (існує) Видалити". Оскільки все ще існує проміжок часу, коли інший потік / процес може повертати файл назад після Видалення, тоді Ви робите свій крок, а в будь-якому випадку отримуєте Виняток. Варто лише мати на увазі :-)
bytedev

11
Ця відповідь все ще діє для більшості людей, які шукають у Google після спроби перезаписати наявний файл. Більшість людей у ​​цьому скрутному становищі не мають проблем із синтаксисом / типом, як OP.
WEFX,

1
@ v.oddou цікаво, якщо файл не існує, File.Delete справді працює коректно і нічого не робить. Якщо натомість жоден з каталогів у шляху не існує, ви отримуєте DirectoryNotFoundException.
Брендон Барклі

2
@JirkaHanika ви можете змінити, якщо (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
Це добре для невеликих файлів (і не вимагає атомного переміщення), але для великих файлів або випадків, коли вам потрібно бути впевненим, що у вас не вийде дублікатів, це проблематично.
Річка Сатья

Чому ви віддаєте перевагу File.Copy , File.Deleteбільше File.Move?
Джон П'єтрар,

6
File.Move не має опції перезапису.
Мітчелл

1
Це може спричинити проблеми залежно від випадку використання. "Переміщення" - це реальна подія в засобі перегляду файлової системи. Щось у списку подій файлової системи буде отримувати подію видалення та створення замість події переміщення. Це також змінить базовий ідентифікатор файлової системи.
Ендрю Рондо

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 як посилання.


Абсолютно добре, якщо програма працює лише у 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 для Move with Overwrite.
Тодд,

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 . Скопіюйте за допомогою Overwrite, а потім видаліть вихідний файл. Це краще, оскільки це робить це атомною операцією. (Я намагався оновити Документи MS цим)


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". між. Це дозволяє переміщати файл, але створює копію, якщо файл вже існує або копія копії вже існує, або копія копії копії існує ...;)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.