File.Move non funziona - Il file esiste già


86

Ho una cartella:

c: \ test

Sto provando questo codice:

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

Ottengo un'eccezione:

Il file esiste già

La directory di output esiste sicuramente e il file di input è lì.


2
Se il file di input è già nella directory di output, il file esiste già, spiegando così l'eccezione. È necessario indicare che si desidera che il file originale venga sovrascritto da quello nuovo.
Cody Grey

9
Sembra che l'errore ti stia dicendo esattamente cosa c'è che non va.
Josh

@ Josh No. Sembra che Windows stia avendo un comportamento del filesystem non POSIX che rende impossibile capire un semplice schema / routine di aggiornamento di file transazionale portatile.
binki

@binki POSIX è irrilevante (stai riferendo alle atomiche operazioni?), NTFS non reali operazioni transazionali di sostegno, come nel rollback-and-get-the-original-file-contenuti-back. Come hanno risposto gli altri, Win32 non consentire movimento con sostituzione. È File.Move di .NET che non fornisce la funzionalità. Puoi ottenere sia Move con sostituzione che operazioni transazionali con librerie come AlphaFS
Panagiotis Kanavos

2
@binki in ogni caso il comportamento è ben definito su diversi file system , indipendentemente da quello che dicono le discussioni nei forum. Il motivo per cui File.Move non chiama i metodi Ex o Transacted è che FAT, che non può essere ignorato poiché è ancora utilizzato dalle schede di memoria, non è atomico e non si comporta allo stesso modo. Le ridenominazioni non sono operazioni di metadati e richiedono lo spostamento effettivo dei dati. E dimentica le transazioni e il copy-on-write. Non una grande decisione imho
Panagiotis Kanavos

Risposte:


62

È necessario spostarlo in un altro file (anziché in una cartella), questo può anche essere utilizzato per rinominare.

Mossa:

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

Rinominare:

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

Il motivo per cui nel tuo esempio viene visualizzato "File già esistente" è perché C:\test\Testtenta di creare un file Testsenza estensione, ma non può farlo perché esiste già una cartella con lo stesso nome.


139

Quello che ti serve è:

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

o

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

Questo può:

  • Se il file non esiste nella posizione di destinazione, spostare correttamente il file o;
  • Se il file esiste nella posizione di destinazione, eliminalo, quindi sposta il file.

Modifica: dovrei chiarire la mia risposta, anche se è la più votata! Il secondo parametro di File.Move dovrebbe essere il file di destinazione , non una cartella. Stai specificando il secondo parametro come cartella di destinazione, non il nome del file di destinazione, che è ciò che File.Move richiede. Quindi, il tuo secondo parametro dovrebbe essere c:\test\Test\SomeFile.txt.


Certamente non ha bisogno di controllare se il file non è lì, perché sta controllando e il file non c'è. L'eccezione è causata dalla mancata aggiunta del nome del file alla cartella di destinazione quando si tenta di spostarlo in un'altra cartella.
Hadi Eskandari

3
Se la tua app è multithread (o ci sono altri processi che lavorano sui tuoi file) potresti comunque ottenere la stessa eccezione anche usando il codice "if (Exists) Delete". Dato che c'è ancora uno spazio di tempo in cui un altro thread / processo potrebbe rimettere un file dopo l'eliminazione, allora fai la tua mossa e quindi ottieni comunque l'eccezione. Vale la pena tenere presente :-)
bytedev

11
Questa risposta è ancora valida per la maggior parte delle persone che google dopo aver provato a sovrascrivere un file esistente. La maggior parte delle persone in questa situazione non ha un problema di sintassi / tipo o come l'OP.
WEFX

1
@ v.oddou interessante, se il file non esiste, File.Delete funziona effettivamente correttamente e non fa nulla. Se invece una qualsiasi delle directory nel percorso non esiste, si ottiene però un'eccezione DirectoryNotFoundException.
Brandon Barkley,

2
@JirkaHanika potresti cambiare if (File.Exists) in while (File.Exists).
Brandon Barkley

39

Personalmente preferisco questo metodo. Ciò sovrascriverà il file nella destinazione, rimuoverà il file di origine e impedirà anche di rimuovere il file di origine quando la copia non riesce.

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
Questo va bene per i file piccoli (e nessun requisito per lo spostamento atomico), ma per i file di grandi dimensioni, o nei casi in cui devi essere sicuro di non finire con i duplicati, è problematico.
River Satya

Perché preferisci File.Copy , File.Deleteoltre File.Move?
John Pietrar

6
File.Move non ha un'opzione di sovrascrittura.
Mitchell

1
A seconda del caso d'uso, ciò può causare problemi. "Move" è un evento reale in un watcher del filesystem. Qualcosa che elenca gli eventi del file system riceverà un evento di eliminazione e di creazione invece di un evento di spostamento. Questo cambierà anche l'ID del filesystem sottostante.
Andrew Rondeau

1
Non sarà molto meno performante per file di grandi dimensioni? Se l'origine e la destinazione si trovano sullo stesso volume fisico, stai creando una seconda copia senza motivo e quindi eliminando l'originale, mentre File.Move () eviterà di eseguire operazioni aggiuntive se l'origine e la destinazione si trovano sullo stesso volume.
Brad Westness

18

Puoi fare un P / Invoke per MoveFileEx()passare 11 per 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);

Oppure puoi semplicemente chiamare

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

dopo aver aggiunto Microsoft.VisualBasic come riferimento.


Benissimo se l'app funziona solo su Windows. Questa è probabilmente una buona risposta per la maggior parte delle persone che sono disposte a provare som P / Invoke.
Todd

9

Se il file esiste davvero e desideri sostituirlo, utilizza il codice seguente:

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

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

File.Move(file, moveTo);

5

1) Con C # su .Net Core 3.0 e versioni successive, ora è disponibile un terzo parametro booleano:

vedere 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) Per tutte le altre versioni di .Net, https://stackoverflow.com/a/42224803/887092 è la risposta migliore. Copia con Sovrascrivi, quindi elimina il file di origine. Questo è meglio perché lo rende un'operazione atomica. (Ho tentato di aggiornare MS Docs con questo)


4

Secondo la documentazione per File.Move non esiste un parametro "sovrascrivi se esiste". Hai provato a specificare la cartella di destinazione , ma devi fornire la specifica completa del file.

Leggendo di nuovo i documenti ("fornendo l'opzione per specificare un nuovo nome di file"), penso che l' aggiunta di una barra rovesciata alle specifiche della cartella di destinazione possa funzionare.


E i documenti menzionano Notare che se si tenta di sostituire un file spostando un file con lo stesso nome in quella directory, viene generata una IOException. A tal fine, chiama Move(String, String, Boolean)invece. ma sembra che sia un errore?
Kevin Scharnhorst

@KevinScharnhorst Questa risposta era del 2011. La documentazione ora include il supporto .Net Core 3.0 per Move with Overwrite.
Todd


1

Se non hai la possibilità di eliminare il file già esistente nella nuova posizione, ma devi comunque spostarlo ed eliminarlo dalla posizione originale, questo trucco di ridenominazione potrebbe funzionare:

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

Questo presuppone l'unico "." nel nome del file è prima dell'estensione. Divide il file in due prima dell'estensione, allega "_copy". nel mezzo. Questo ti consente di spostare il file, ma crea una copia se il file esiste già o una copia della copia esiste già, o una copia della copia della copia esiste ...;)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.