¿Cómo mover un archivo?

910

Miré en la osinterfaz de Python , pero no pude encontrar un método para mover un archivo. ¿Cómo haría el equivalente de $ mv ...en Python?

>>> source_files = '/PATH/TO/FOLDER/*'
>>> destination_folder = 'PATH/TO/FOLDER'
>>> # equivalent of $ mv source_files destination_folder
David542
fuente
1
Para aquellos de ustedes que están familiarizados con el mvcomando de gnu-coreutils , Python shutil.movetiene un caso extremo donde la shutil.movefunción difiere. Vaya aquí para una redacción completa . En pocas palabras, Python shutil.movegenerará una excepción (pero gnu-coreutils mvno lo hará) cuando su destino sea un directorio y el directorio ya tenga un archivo con el mismo nombre que la fuente (nuevamente para obtener más información, consulte el enlace proporcionado en la oración anterior) )
Trevor Boyd Smith
3
¿Qué tal os.system("mv file1 file2")?
John Strood

Respuestas:

1340

os.rename()` shutil.move()` oos.replace()

Todos emplean la misma sintaxis:

import os
import shutil

os.rename("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")
os.replace("path/to/current/file.foo", "path/to/new/destination/for/file.foo")

Tenga en cuenta que debe incluir el nombre del archivo ( file.foo) en los argumentos de origen y destino. Si se cambia, el archivo cambiará de nombre y se moverá.

Tenga en cuenta también que en los dos primeros casos, el directorio en el que se está creando el nuevo archivo ya debe existir. En Windows, un archivo con ese nombre no debe existir o se generará una excepción, pero os.replace()reemplazará silenciosamente un archivo incluso en ese caso.

Como se ha señalado en los comentarios sobre otras respuestas, shutil.movesimplemente llama os.renameen la mayoría de los casos. Sin embargo, si el destino está en un disco diferente al de origen, en su lugar, copiará y luego eliminará el archivo de origen.

ig0774
fuente
8
¿Soy el único que piensa que os.rename no funciona para directorios? Cito: "Si dst es un directorio, se generará OSError".
Fabian
33
shutil.moveFunciona para directorios. Puede usar la ruta relativa shutil.move(f.name, "tmp/")o la ruta completa shutil.move(f.name, "/Users/hello/tmp/"), no la use ~ en la ruta, verificada en python2.7.9, Mac OS X.
whyisyoung
3
~es una construcción de shell y no tiene nada que ver con las rutas de archivo per se, aparte de una convención fuera de lugar. Si realmente desea involucrar su directorio de inicio, use os.getenv('HOME')en su lugar, concatenando con partes de su ruta deseada, si es necesario.
amn
15
Siempre puede usar os.path.expanduser()para expandir correctamente el ' ~' de acuerdo con las reglas específicas del sistema operativo. Mucho más ordenado ya %HOME%que no siempre está configurado en Windows.
ig0774
14
os.renameno manejará archivos en diferentes dispositivos. Úselo shutil.movesi no está seguro de que el archivo de origen y el de destino están en el mismo dispositivo.
Giuseppe Scrivano
244

Aunque os.rename()y shutil.move()cambiará el nombre de los archivos, el comando más cercano al comando Unix mv es shutil.move(). La diferencia es que os.rename()no funciona si el origen y el destino están en discos diferentes, mientras que shutil.move()no le importa en qué disco están los archivos.

Jim Calfas
fuente
75
shutil.move()se usa os.rename()si el destino está en el sistema de archivos actual. De lo contrario, shutil.move()copia el origen al destino usando shutil.copy2()y luego elimina el origen.
salto de línea el
8
Tenga cuidado de darse cuenta de que shutil.copy2()no se pueden copiar todos los metadatos de los archivos , por lo que si eso sucede es como hacerlo cp -py luego rm, me reúno.
2rs2ts
99
Tenga en cuenta: shutil.move en Python 2.7.3 falla si el destino ya existe. Entonces, si eso es posible, detecte el error o elimine manualmente el archivo / directorio, luego realice el movimiento.
Dana
36

Para os.rename o shutil.move, deberá importar el módulo. No es necesario un carácter * para mover todos los archivos.

Tenemos una carpeta en / opt / awesome llamada fuente con un archivo llamado awesome.txt.

in /opt/awesome
  ls
source
  ls source
awesome.txt

python 
>>> source = '/opt/awesome/source'
>>> destination = '/opt/awesome/destination'
>>> import os
>>> os.rename(source, destination)
>>> os.listdir('/opt/awesome')
['destination']

Usamos os.listdir para ver que el nombre de la carpeta de hecho cambió. Aquí está el shutil moviendo el destino de regreso a la fuente.

>>> import shutil
>>> shutil.move(destination, source)
>>> os.listdir('/opt/awesome/source')
['awesome.txt']

Esta vez revisé dentro de la carpeta de origen para asegurarme de que existe el archivo awesome.txt que creé. Está ahí :)

Ahora hemos movido una carpeta y sus archivos de una fuente a un destino y viceversa.

jmontross
fuente
44
docs.python.org/2/library/shutil.html Esta documentación muestra que ha cambiado sus parámetros para el método shutil.move.
mac10688
1
Utilicé el destino y la fuente invertidos para ver que los archivos se movieron de la fuente y luego volví a ellos ... Pude ver cómo eso no está claro.
jmontross
14

Esto es lo que estoy usando en este momento:

import os, shutil
path = "/volume1/Users/Transfer/"
moveto = "/volume1/Users/Drive_Transfer/"
files = os.listdir(path)
files.sort()
for f in files:
    src = path+f
    dst = moveto+f
    shutil.move(src,dst)

Ahora completamente funcional. Espero que esto te ayude.

Editar:

He convertido esto en una función, que acepta un directorio de origen y destino, haciendo la carpeta de destino si no existe, y mueve los archivos. También permite el filtrado de los archivos src, por ejemplo, si solo desea mover imágenes, entonces usa el patrón '*.jpg', de forma predeterminada, mueve todo en el directorio

import os, shutil, pathlib, fnmatch

def move_dir(src: str, dst: str, pattern: str = '*'):
    if not os.path.isdir(dst):
        pathlib.Path(dst).mkdir(parents=True, exist_ok=True)
    for f in fnmatch.filter(os.listdir(src), pattern):
        shutil.move(os.path.join(src, f), os.path.join(dst, f))
Peter Vlaar
fuente
1
Puedes convertir esto fácilmente en un movimiento filtrado usando fnmatch.filter (), mira mi edición. Además, lo mejor es utilizar os.path.join(parent_path, filename)en lugar de la concatenación de cadenas para evitar problemas multiplataforma
iggy12345
11

La respuesta aceptada no es la correcta, porque la pregunta no es cambiar el nombre de un archivo a un archivo, sino mover muchos archivos a un directorio. shutil.movehará el trabajo, pero para este propósito os.renamees inútil (como se indica en los comentarios) porque el destino debe tener un nombre de archivo explícito.

Javier Palacios
fuente
No es inútil, simplemente requiere más trabajo para mover varios archivos. Puede obtener nombres de archivos con os.path.basename(my_file_path)y los directorios de archivos con os.path.dirname(my_file_path). Además, el OP no dejó muy claro si quería mover varios archivos. Mencionó mover solo un archivo en la pregunta, pero su código de ejemplo implicaba mover múltiples archivos.
Jacques Mathieu
2

Según la respuesta que se describe aquí , usar subprocesses otra opción.

Algo como esto:

subprocess.call("mv %s %s" % (source_files, destination_folder), shell=True)

Tengo curiosidad por saber las ventajas y desventajas de este método en comparación shutil. Como en mi caso ya lo estoy usando subprocesspor otros motivos y parece funcionar, me inclino a seguir con él.

¿Es dependiente del sistema tal vez?

Cuenta
fuente
2
Creo que esto dependería del sistema. No veo que mvse use con éxito en un sistema operativo Windows.
Joshua Schlichting
0

Esta es la solución, que no permite el shelluso mv.

import subprocess

source      = 'pathToCurrent/file.foo'
destination = 'pathToNew/file.foo'

p = subprocess.Popen(['mv', source, destination], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
res = p.communicate()[0].decode('utf-8').strip()

if p.returncode:
    print 'ERROR: ' + res
alper
fuente
-2
  import os,shutil

  current_path = "" ## source path

  new_path = "" ## destination path

  os.chdir(current_path)

  for files in os.listdir():

        os.rename(files, new_path+'{}'.format(f))
        shutil.move(files, new_path+'{}'.format(f)) ## to move files from 

disco diferente ej. C: -> D:

Ned Slark
fuente
si está usando Python3. # puede usar la nueva integración de cadenas f: f"{new_path}{f}"pero dado que no tiene texto estático en su cadena, esto puede ser más trabajo ... He estado tratando de acostumbrarme a usar cuerdas f sin embargo.
jusopi
¿Te refieres a archivo en lugar de f?
Matthew