File.Move nie działa - plik już istnieje

86

Mam folder:

c: \ test

Próbuję tego kodu:

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

Dostaję wyjątek:

plik już istnieje

Katalog wyjściowy na pewno istnieje i plik wejściowy tam jest.

Jack Kada
źródło
2
Jeśli plik wejściowy znajduje się już w katalogu wyjściowym, oznacza to, że plik już istnieje, co wyjaśnia wyjątek. Musisz wskazać, że chcesz zastąpić oryginalny plik nowym.
Cody Gray
9
Wygląda na to, że błąd mówi dokładnie, co jest nie tak.
Josh
@Josh Nie. Wygląda na to, że Windows zachowuje się w systemie plików innym niż POSIX, co uniemożliwia znalezienie prostego, przenośnego schematu / procedury aktualizacji plików transakcyjnych.
binki
@binki POSIX nie ma znaczenia (czy nawiązujące do atomowych operacji?), NTFS ma wsparcia prawdziwych operacji transakcyjnych, jak w wycofywania-and-get-the-oryginalny plik-content-plecy. Jak inni odpowiedział Win32 nie pozwalają przenieść się zastąpić. To nie jest File.Move .NET, który nie zapewnia funkcjonalności. Możesz uzyskać zarówno Move with replace, jak i operacje transakcyjne z bibliotekami takimi jak AlphaFS
Panagiotis Kanavos
2
@binki w każdym razie zachowanie jest dobrze zdefiniowane w różnych systemach plików , niezależnie od tego, co mówią dyskusje na forach. Powodem, dla którego File.Move nie wywołuje metod Ex ani Transacted, jest to, że FAT, którego nie można zignorować, ponieważ nadal jest używany przez karty pamięci, nie jest atomowy i nie zachowuje się tak samo. Zmiany nazw nie są operacjami na metadanych i wymagają rzeczywistego przenoszenia danych. I zapomnij o transakcjach i kopiowaniu przy zapisie. Niezbyt dobra decyzja imho
Panagiotis Kanavos

Odpowiedzi:

62

Musisz przenieść go do innego pliku (zamiast do folderu), można tego również użyć do zmiany nazwy.

Ruszaj się:

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

Przemianować:

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

Powodem, dla którego w Twoim przykładzie jest napisane „Plik już istnieje”, jest C:\test\Testpróba utworzenia pliku Testbez rozszerzenia, ale nie może tego zrobić, ponieważ istnieje już folder o tej samej nazwie.

Zawietrzny
źródło
138

Potrzebujesz:

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

lub

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");

Spowoduje to:

  • Jeśli plik nie istnieje w lokalizacji docelowej, pomyślnie przenieś plik lub;
  • Jeśli plik istnieje w lokalizacji docelowej, usuń go, a następnie przenieś.

Edycja: Powinienem wyjaśnić moją odpowiedź, mimo że jest najbardziej pozytywna! Drugim parametrem File.Move powinien być plik docelowy - nie folder. Określasz drugi parametr jako folder docelowy, a nie docelową nazwę pliku - tego wymaga File.Move. Zatem twoim drugim parametrem powinien być c:\test\Test\SomeFile.txt.

Jamie Howarth
źródło
Z pewnością nie musi sprawdzać, czy pliku tam nie ma, ponieważ sprawdza, a pliku tam nie ma. Wyjątek jest spowodowany tym, że nazwa pliku nie jest dołączana do folderu docelowego podczas próby przeniesienia go do innego folderu.
Hadi Eskandari
3
Jeśli Twoja aplikacja jest wielowątkowa (lub inne procesy działają na twoich plikach), prawdopodobnie nadal możesz uzyskać ten sam wyjątek, nawet używając kodu „if (Exists) Delete”. Ponieważ nadal istnieje czas, w którym inny wątek / proces może wstawiać plik z powrotem po usunięciu, wykonujesz ruch, a następnie mimo wszystko otrzymujesz wyjątek. Warto o tym pamiętać :-)
bytedev
11
Ta odpowiedź jest nadal ważna dla większości ludzi, którzy szukają w Google po próbie nadpisania istniejącego pliku. Większość ludzi w tej sytuacji nie ma problemu ze składnią / typem o, tak jak w przypadku OP.
WEFX
1
@ v.oddou ciekawe, jeśli plik nie istnieje, File.Delete rzeczywiście działa poprawnie i nic nie robi. Jeśli zamiast tego żaden z katalogów w ścieżce nie istnieje, zostanie wyświetlony wyjątek DirectoryNotFoundException.
Brandon Barkley
2
@JirkaHanika możesz zmienić if (File.Exists) na while (File.Exists).
Brandon Barkley
38

Osobiście wolę tę metodę. Spowoduje to nadpisanie pliku w miejscu docelowym, usunięcie pliku źródłowego, a także zapobiegnie usunięciu pliku źródłowego w przypadku niepowodzenia kopiowania.

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
}
Mitchell
źródło
4
Jest to w porządku w przypadku małych plików (i nie wymaga atomowego przenoszenia), ale w przypadku dużych plików lub przypadków, w których musisz mieć pewność, że nie zostaną duplikaty, jest to problematyczne.
Rzeka Satya
Dlaczego wolisz File.Copy , File.Deletenad File.Move?
John Pietrar,
6
File.Move nie ma opcji nadpisywania.
Mitchell,
1
W zależności od przypadku użycia może to powodować problemy. „Przenieś” to prawdziwe zdarzenie w obserwatorze systemu plików. Coś, co zawiera listę zdarzeń systemu plików, otrzyma zdarzenie usuwania i tworzenia zamiast zdarzenia przeniesienia. Spowoduje to również zmianę podstawowego identyfikatora systemu plików.
Andrew Rondeau
1
Czy nie będzie to dużo mniej wydajne w przypadku dużych plików? Jeśli źródło i miejsce docelowe znajdują się na tym samym woluminie fizycznym, tworzysz drugą kopię bez powodu, a następnie usuwasz oryginał, podczas gdy File.Move () pozwoli uniknąć dodatkowej pracy, jeśli źródło i miejsce docelowe znajdują się na tym samym woluminie.
Brad Westness
18

Możesz wykonać P / Invoke to MoveFileEx()- pass 11 for 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);

Możesz też po prostu zadzwonić

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

po dodaniu Microsoft.VisualBasic jako odniesienia.

mheyman
źródło
Całkowicie w porządku, jeśli aplikacja działa tylko w systemie Windows. To prawdopodobnie dobra odpowiedź dla większości ludzi, którzy chcą spróbować P / Invoke.
Todd
9

Jeśli plik naprawdę istnieje i chcesz go zastąpić użyj poniższego kodu:

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

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

File.Move(file, moveTo);
Paweł Czapski
źródło
4

Zgodnie z dokumentacją File.Move nie ma parametru „nadpisać, jeśli istnieje”. Próbowałeś określić folder docelowy , ale musisz podać pełną specyfikację pliku.

Czytając dokumenty ponownie („zapewniając opcję określenia nowej nazwy pliku”), myślę , że dodanie ukośnika odwrotnego do specyfikacji folderu docelowego może działać.

Ekkehard.Horner
źródło
Dokumenty wspominają, że jeśli spróbujesz zastąpić plik, przenosząc plik o tej samej nazwie do tego katalogu, zostanie wyrzucony wyjątek IOException. W tym celu zadzwoń Move(String, String, Boolean). ale wydaje się, że to pomyłka?
Kevin Scharnhorst
@KevinScharnhorst Ta odpowiedź to rok 2011. Dokumentacja zawiera teraz obsługę .Net Core 3.0 dla funkcji Move with Overwrite.
Todd
4

1) W przypadku języka C # w .Net Core 3.0 i nowszych jest teraz trzeci parametr boolowski:

zobacz 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) W przypadku wszystkich innych wersji .Net, https://stackoverflow.com/a/42224803/887092 jest najlepszą odpowiedzią. Skopiuj z Zastąp, a następnie usuń plik źródłowy. To jest lepsze, ponieważ sprawia, że ​​jest to operacja atomowa. (Próbowałem zaktualizować dokumenty MS za pomocą tego)

Todd
źródło
2

Spróbuj Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). Ostatnim parametrem jest przełącznik Overwrite, którego System.IO.File.Movenie ma.

znak
źródło
2
Jest już tutaj inna odpowiedź, która jest podobna, która sugeruje ten sam stackoverflow.com/a/42224803/1236734
JG w SD
To jest odpowiedź, która sugeruje to samo: stackoverflow.com/a/38372760/887092 , a nie stackoverflow.com/a/42224803/1236734
Todd
1

Jeśli nie masz opcji usunięcia już istniejącego pliku w nowej lokalizacji, ale nadal musisz przenieść i usunąć z oryginalnej lokalizacji, ta sztuczka zmiany nazwy może zadziałać:

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);

To zakłada jedyny „.” w nazwie pliku znajduje się przed rozszerzeniem. Dzieli plik na dwie części przed rozszerzeniem i dołącza „_copy”. pomiędzy. Pozwala to przenieść plik, ale tworzy kopię, jeśli plik już istnieje lub kopia kopii już istnieje, lub kopia kopii kopii istnieje ...;)

Myszkować
źródło