File.Move funktioniert nicht - Datei existiert bereits

84

Ich habe einen Ordner:

c: \ test

Ich versuche diesen Code:

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

Ich bekomme eine Ausnahme:

Die Datei existiert bereits

Das Ausgabeverzeichnis existiert definitiv und die Eingabedatei ist da.

Jack Kada
quelle
2
Befindet sich die Eingabedatei bereits im Ausgabeverzeichnis, ist die Datei bereits vorhanden, wodurch die Ausnahme erläutert wird. Sie müssen angeben, dass die Originaldatei durch die neue überschrieben werden soll.
Cody Gray
9
Klingt so, als würde der Fehler Ihnen genau sagen, was falsch ist.
Josh
@Josh Nein. Es hört sich so an, als ob Windows ein Nicht-POSIX-Dateisystemverhalten aufweist, das es unmöglich macht, ein einfaches Muster / eine Routine für die Aktualisierung von tragbaren Transaktionsdateien herauszufinden.
Binki
@binki POSIX irrelevant ist (sind Sie beziehen atomare Operationen?), NTFS funktioniert Unterstützung reale Transaktionsvorgänge, wie in Rollback-und-get-the-Original-Datei-Inhalt-back. Wie andere geantwortet haben, erlaubt Win32 das Verschieben mit Ersetzen. Es ist .NETs File.Move, das nicht die Funktionalität bietet. Sie können sowohl Verschieben mit Ersetzen als auch Transaktionsoperationen mit Bibliotheken wie AlphaFS
Panagiotis Kanavos
2
@binki in jedem Fall ist das Verhalten auf verschiedenen Dateisystemen gut definiert , egal was Forendiskussionen sagen. Der Grund, warum File.Move die Ex- oder Transacted-Methoden nicht aufruft, ist, dass FAT, das nicht ignoriert werden kann, da es immer noch von Speicherkarten verwendet wird, nicht atomar ist und sich nicht gleich verhält. Umbenennungen sind keine Metadatenoperationen und erfordern eine tatsächliche Datenverschiebung. Und vergessen Sie Transaktionen und Copy-on-Write. Keine gute Entscheidung imho
Panagiotis Kanavos

Antworten:

61

Sie müssen es in eine andere Datei (anstatt in einen Ordner) verschieben. Dies kann auch zum Umbenennen verwendet werden.

Bewegung:

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

Umbenennen:

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

In Ihrem Beispiel heißt es "Datei existiert bereits", weil C:\test\Testversucht wird, eine Datei Testohne Erweiterung zu erstellen , dies jedoch nicht möglich ist, da bereits ein Ordner mit demselben Namen vorhanden ist.

Lee
quelle
136

Was Sie brauchen ist:

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

oder

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

Dies wird entweder:

  • Wenn die Datei am Zielspeicherort nicht vorhanden ist, verschieben Sie die Datei erfolgreich, oder;
  • Wenn die Datei am Zielspeicherort vorhanden ist, löschen Sie sie und verschieben Sie die Datei.

Bearbeiten: Ich sollte meine Antwort klarstellen, obwohl es die am besten bewertete ist! Der zweite Parameter von File.Move sollte die seine Zieldatei - nicht einen Ordner. Sie geben den zweiten Parameter als Zielordner an , nicht den Zieldateinamen - was File.Move erfordert. Ihr zweiter Parameter sollte also sein c:\test\Test\SomeFile.txt.

Jamie Howarth
quelle
Sicherlich muss nicht überprüft werden, ob die Datei nicht vorhanden ist, da er überprüft und die Datei nicht vorhanden ist. Die Ausnahme wird dadurch verursacht, dass der Dateiname nicht an den Zielordner angehängt wird, wenn versucht wird, ihn in einen anderen Ordner zu verschieben.
Hadi Eskandari
3
Wenn Ihre App über mehrere Threads verfügt (oder andere Prozesse an Ihren Dateien arbeiten), können Sie möglicherweise immer noch dieselbe Ausnahme erhalten, selbst wenn Sie den Code "if (Exists) Delete" verwenden. Da es noch einen Zeitraum gibt, in dem ein anderer Thread / Prozess nach dem Löschen eine Datei zurücklegen könnte, führen Sie Ihren Umzug durch und erhalten trotzdem die Ausnahme. Es lohnt sich nur daran zu denken :-)
bytedev
11
Diese Antwort gilt weiterhin für die meisten Google-Nutzer, die versucht haben, eine vorhandene Datei zu überschreiben. Die meisten Menschen in dieser Situation haben kein Syntax- / Typ-O-Problem wie das OP.
WEFX
1
@ v.oddou Interessanterweise funktioniert File.Delete tatsächlich korrekt und unternimmt nichts, wenn die Datei nicht vorhanden ist. Wenn stattdessen keines der Verzeichnisse im Pfad vorhanden ist, erhalten Sie jedoch eine DirectoryNotFoundException.
Brandon Barkley
2
@JirkaHanika Sie können if (File.Exists) in while (File.Exists) ändern.
Brandon Barkley
37

Persönlich bevorzuge ich diese Methode. Dadurch wird die Datei auf dem Ziel überschrieben, die Quelldatei entfernt und das Entfernen der Quelldatei verhindert, wenn die Kopie fehlschlägt.

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
quelle
4
Dies ist in Ordnung für kleine Dateien (und keine Notwendigkeit für atomare Verschiebungen), aber für große Dateien oder Fälle, in denen Sie sicher sein müssen, dass Sie keine Duplikate erhalten, ist dies problematisch.
Fluss Satya
Warum ziehst du es File.Copy , File.Deletevor File.Move?
John Pietrar
6
File.Move hat keine Überschreiboption.
Mitchell
1
Abhängig von Ihrem Anwendungsfall kann dies zu Problemen führen. "Verschieben" ist ein echtes Ereignis in einem Dateisystem-Watcher. Eine Auflistung von Dateisystemereignissen wird ein Lösch- und ein Erstellungsereignis anstelle eines Verschiebungsereignisses erhalten. Dadurch wird auch die zugrunde liegende Dateisystem-ID geändert.
Andrew Rondeau
1
Wird dies bei großen Dateien nicht viel weniger leistungsfähig sein? Wenn sich Quelle und Ziel auf demselben physischen Volume befinden, erstellen Sie ohne Grund eine zweite Kopie und löschen dann das Original, während File.Move () zusätzliche Arbeit vermeidet, wenn sich Quelle und Ziel auf demselben Volume befinden.
Brad Westness
18

Sie können ein P / Invoke durchführen, MoveFileEx()um 11 für flags( MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) zu übergeben.

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

Oder Sie können einfach anrufen

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

nach dem Hinzufügen von Microsoft.VisualBasic als Referenz.

Mheyman
quelle
Völlig in Ordnung, wenn die App nur unter Windows ausgeführt wird. Dies ist wahrscheinlich eine gute Antwort für die meisten Leute, die bereit sind, etwas P / Invoke auszuprobieren.
Todd
9

Wenn die Datei wirklich vorhanden ist und Sie sie ersetzen möchten, verwenden Sie den folgenden Code:

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

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

File.Move(file, moveTo);
Pawel Czapski
quelle
4

Gemäß den Dokumenten für File.Move gibt es keinen Parameter "Überschreiben, falls vorhanden". Sie haben versucht, den Zielordner anzugeben , müssen jedoch die vollständige Dateispezifikation angeben .

Beim Lesen der wieder docs ( „die Möglichkeit , die Bereitstellung eines neuen Dateinamen angeben“), ich denke , kann arbeiten , um einen umgekehrten Schrägstrich in den Zielordner spec hinzufügen.

Ekkehard.Horner
quelle
In den Dokumenten wird Folgendes erwähnt : Wenn Sie versuchen, eine Datei durch Verschieben einer gleichnamigen Datei in dieses Verzeichnis zu ersetzen, wird eine IOException ausgelöst. Rufen Sie Move(String, String, Boolean)stattdessen an. aber das scheint ein fehler zu sein?
Kevin Scharnhorst
@ KevinScharnhorst Diese Antwort war 2011. Die Dokumentation enthält jetzt .Net Core 3.0-Unterstützung für Move with Overwrite.
Todd
3

1) Mit C # auf .Net Core 3.0 und höher gibt es jetzt einen dritten booleschen Parameter:

Siehe 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) Für alle anderen Versionen von .Net ist https://stackoverflow.com/a/42224803/887092 die beste Antwort. Kopieren Sie mit Überschreiben und löschen Sie die Quelldatei. Dies ist besser, weil es eine atomare Operation ist. (Ich habe versucht, die MS Docs damit zu aktualisieren)

Todd
quelle
2

Versuchen Sie es Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). Der letzte Parameter ist der Overwrite-Schalter, der System.IO.File.Movenicht vorhanden ist.

Kennzeichen
quelle
2
Es gibt bereits eine ähnliche Antwort, die den gleichen stackoverflow.com/a/42224803/1236734
JG in SD
Dies ist die Antwort, die dasselbe vorschlägt : stackoverflow.com/a/38372760/887092 , nicht stackoverflow.com/a/42224803/1236734
Todd
1

Wenn Sie nicht die Option haben, die bereits vorhandene Datei am neuen Speicherort zu löschen, aber dennoch verschoben und vom ursprünglichen Speicherort gelöscht werden müssen, funktioniert dieser Umbenennungstrick möglicherweise:

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

Dies setzt das einzige '.' im Dateinamen steht vor der Erweiterung. Es teilt die Datei vor der Erweiterung in zwei Teile und fügt "_copy" hinzu. zwischen. Auf diese Weise können Sie die Datei verschieben, aber eine Kopie erstellen, wenn die Datei bereits vorhanden ist oder eine Kopie der Kopie bereits vorhanden ist oder eine Kopie der Kopie der Kopie vorhanden ist ...;)

Gieren
quelle