File.Move no funciona: el archivo ya existe

86

Tengo una carpeta:

c: \ prueba

Estoy probando este código:

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

Obtengo una excepción:

El archivo ya existe

El directorio de salida definitivamente existe y el archivo de entrada está allí.

Jack Kada
fuente
2
Si el archivo de entrada ya está en el directorio de salida, entonces el archivo ya existe, lo que explica la excepción. Debe indicar que desea que el archivo original se sobrescriba con el nuevo.
Cody Gray
9
Parece que el error te dice exactamente lo que está mal.
Josh
@ Josh No. Parece que Windows está teniendo un comportamiento del sistema de archivos que no es POSIX, lo que hace imposible descubrir un patrón / rutina de actualización de archivos transaccionales portátil simple.
binki
@binki POSIX es irrelevante (estás refiriendo a atómicas operaciones?), NTFS hace operaciones transaccionales reales de apoyo, como en rollback-y-conseguir-la-original de un archivo de contenido de la espalda. Como respondieron otros, Win32 hace permitir movimiento con sustituir. Es File.Move de .NET que no proporciona la funcionalidad. Puede obtener tanto Move con reemplazo como operaciones transaccionales con bibliotecas como AlphaFS
Panagiotis Kanavos
2
@binki en cualquier caso, el comportamiento está bien definido en diferentes sistemas de archivos , sin importar lo que digan las discusiones de los foros. La razón por la que File.Move no llama a los métodos Ex o Transacted es que FAT, que no se puede ignorar ya que todavía lo usan las tarjetas de memoria, no es atómico y no se comporta de la misma manera. Los cambios de nombre no son operaciones de metadatos y requieren un movimiento de datos real. Y olvídese de las transacciones y la copia en escritura. No es una gran decisión en mi humilde opinión
Panagiotis Kanavos

Respuestas:

62

Debe moverlo a otro archivo (en lugar de a una carpeta), esto también se puede usar para cambiar el nombre.

Moverse:

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

Rebautizar:

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

La razón por la que dice "El archivo ya existe" en su ejemplo es porque C:\test\Testintenta crear un archivo Testsin una extensión, pero no puede hacerlo porque ya existe una carpeta con el mismo nombre.

Sotavento
fuente
138

Lo que necesitas es:

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

Esto hará lo siguiente:

  • Si el archivo no existe en la ubicación de destino, mueva correctamente el archivo o;
  • Si el archivo existe en la ubicación de destino, elimínelo y luego mueva el archivo.

Editar: ¡Debería aclarar mi respuesta, aunque es la más votada! El segundo parámetro de File.Move debe ser el archivo de destino , no una carpeta. Está especificando el segundo parámetro como la carpeta de destino, no el nombre del archivo de destino, que es lo que requiere File.Move. Entonces, su segundo parámetro debería ser c:\test\Test\SomeFile.txt.

Jamie Howarth
fuente
Ciertamente, no es necesario verificar si el archivo no está allí, porque está comprobando y el archivo no está allí. La excepción se debe a que no se agrega el nombre del archivo a la carpeta de destino cuando se intenta moverlo a otra carpeta.
Hadi Eskandari
3
Si su aplicación tiene varios subprocesos (o hay otros procesos trabajando en sus archivos), es posible que aún obtenga la misma excepción incluso usando el código "si (existe) eliminar". Como todavía hay un espacio de tiempo en el que otro hilo / proceso podría volver a colocar un archivo después de Eliminar, entonces usted hace su movimiento y luego obtiene la Excepción de todos modos. Vale la pena
tenerlo
11
Esta respuesta sigue siendo válida para la mayoría de las personas que buscan en Google después de intentar sobrescribir un archivo existente. La mayoría de las personas en esta situación no tienen un problema de sintaxis / tipo-o como el OP.
WEFX
1
@ v.oddou curiosamente, si el archivo no existe, File.Delete funciona correctamente y no hace nada. Sin embargo, si alguno de los directorios de la ruta no existe, obtendrá una excepción DirectoryNotFoundException.
Brandon Barkley
2
@JirkaHanika, podría cambiar si (Archivo.Existe) por mientras (Archivo.Existe).
Brandon Barkley
38

Personalmente prefiero este método. Esto sobrescribirá el archivo en el destino, eliminará el archivo de origen y también evitará eliminar el archivo de origen cuando falla la copia.

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
fuente
4
Esto está bien para archivos pequeños (y no requiere movimiento atómico), pero para archivos grandes, o casos en los que necesita asegurarse de que no terminará con duplicados, es problemático.
Río Satya
¿Por qué prefieres File.Copy , File.Deletemás File.Move?
John Pietrar
6
File.Move no tiene una opción de sobrescritura.
Mitchell
1
Dependiendo de su caso de uso, esto puede causar problemas. "Move" es un evento real en un observador de sistemas de archivos. Algo que se incluya en los eventos del sistema de archivos obtendrá un evento de eliminación y creación en lugar de un evento de movimiento. Esto también cambiará el ID del sistema de archivos subyacente.
Andrew Rondeau
1
¿No será mucho menos eficaz para archivos grandes? Si la fuente y el destino están en el mismo volumen físico, está creando una segunda copia sin ningún motivo y luego eliminando el original, mientras que File.Move () evitará hacer trabajo adicional si la fuente y el destino están en el mismo volumen.
Brad Westness
18

Puede hacer un P / Invoke para MoveFileEx()- pase 11 para 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);

O puedes simplemente llamar

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

después de agregar Microsoft.VisualBasic como referencia.

mheyman
fuente
Totalmente bien si la aplicación solo se ejecuta en Windows. Esta es probablemente una buena respuesta para la mayoría de las personas que estén dispuestas a probar som P / Invoke.
Todd
9

Si el archivo realmente existe y desea reemplazarlo, use el siguiente código:

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
fuente
4

De acuerdo con los documentos de File.Move, no existe el parámetro "sobrescribir si existe". Intentaste especificar la carpeta de destino , pero debe proporcionar la especificación completa del archivo.

Al leer los documentos nuevamente ("brindando la opción de especificar un nuevo nombre de archivo"), creo que agregar una barra invertida a la especificación de la carpeta de destino puede funcionar.

Ekkehard.Horner
fuente
Y los documentos mencionan Tenga en cuenta que si intenta reemplazar un archivo moviendo un archivo con el mismo nombre a ese directorio, se lanza una IOException. Para ese propósito, llame en su Move(String, String, Boolean)lugar. pero eso parece ser un error?
Kevin Scharnhorst
@KevinScharnhorst Esta respuesta fue 2011. La documentación ahora incluye compatibilidad con .Net Core 3.0 para Move with Overwrite.
Todd
4

1) Con C # en .Net Core 3.0 y posteriores, ahora hay un tercer parámetro booleano:

ver 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) Para todas las demás versiones de .Net, https://stackoverflow.com/a/42224803/887092 es la mejor respuesta. Copie con Overwrite, luego elimine el archivo de origen. Esto es mejor porque lo convierte en una operación atómica. (He intentado actualizar MS Docs con esto)

Todd
fuente
2

Prueba Microsoft.VisualBasic.FileIO.FileSystem.MoveFile(Source, Destination, True). El último parámetro es el conmutador Overwrite, que System.IO.File.Moveno tiene.

marca
fuente
2
Ya hay otra respuesta aquí que es similar que sugiere el mismo stackoverflow.com/a/42224803/1236734
JG en SD
Esta es la respuesta que sugiere lo mismo: stackoverflow.com/a/38372760/887092 , no stackoverflow.com/a/42224803/1236734
Todd
1

Si no tiene la opción de eliminar el archivo ya existente en la nueva ubicación, pero aún necesita moverlo y eliminarlo de la ubicación original, este truco de cambio de nombre podría funcionar:

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

Esto asume el único '.' en el nombre del archivo está antes de la extensión. Divide el archivo en dos antes de la extensión, adjunta "_copy". entre. Esto le permite mover el archivo, pero crea una copia si el archivo ya existe o ya existe una copia de la copia, o existe una copia de la copia de la copia ...;)

Guiñada
fuente