Como mover um arquivo?

909

Examinei a osinterface do Python , mas não consegui localizar um método para mover um arquivo. Como eu faria o equivalente $ mv ...em Python?

>>> source_files = '/PATH/TO/FOLDER/*'
>>> destination_folder = 'PATH/TO/FOLDER'
>>> # equivalent of $ mv source_files destination_folder
David542
fonte
1
para aqueles que conhecem o mvcomando do gnu-coreutils , o python's shutil.movetem um caso de borda em que a shutil.movefunção difere. Clique aqui para obter a gravação completa . Em poucas palavras, o Python shutil.movecriará uma exceção (mas o gnu-coreutils mvnão) quando o seu destino for um diretório e o diretório já tiver um arquivo com o mesmo nome que a fonte (novamente, para obter mais informações, consulte o link fornecido na frase anterior). )
Trevor Boyd Smith
3
Que tal os.system("mv file1 file2")?
John Strood

Respostas:

1340

os.rename(), shutil.move()ouos.replace()

Todos empregam a mesma sintaxe:

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

Observe que você deve incluir o nome do arquivo ( file.foo) nos argumentos de origem e de destino. Se for alterado, o arquivo será renomeado e movido.

Observe também que nos dois primeiros casos o diretório no qual o novo arquivo está sendo criado já deve existir. No Windows, um arquivo com esse nome não deve existir ou uma exceção será gerada, mas os.replace()substituirá silenciosamente um arquivo mesmo nessa ocorrência.

Como foi observado nos comentários sobre outras respostas, shutil.movebasta ligar os.renamena maioria dos casos. No entanto, se o destino estiver em um disco diferente da fonte, ele copiará e excluirá o arquivo de origem.

ig0774
fonte
8
Eu sou o único que acha que os.rename não está funcionando para diretórios? Cito: "Se dst for um diretório, o OSError será gerado."
Fabian
33
shutil.movetrabalha para diretórios. Você pode usar o caminho relativo shutil.move(f.name, "tmp/")ou caminho completo shutil.move(f.name, "/Users/hello/tmp/"), não use ~ no caminho, o check-in python2.7.9, Mac OS X.
whyisyoung
3
~é uma construção shell e não tem nada a ver com os caminhos de arquivo em si, exceto como uma convenção extraviada. Se você realmente deseja envolver seu diretório pessoal, use-o os.getenv('HOME'), concatenando-o com partes do caminho desejado, se necessário.
01:
15
Você sempre pode usar os.path.expanduser()para expandir adequadamente o ' ~' de acordo com regras específicas do sistema operacional. Muito mais organizado, pois %HOME%nem sempre é definido no Windows.
00009 igrejamento
14
os.renamenão manipula arquivos em diferentes dispositivos. Use shutil.movese você não tiver certeza de que a fonte e o arquivo de destino estão no mesmo dispositivo.
Giuseppe Scrivano
244

Embora os.rename()e shutil.move()renomeiem os arquivos, o comando mais próximo do comando Unix mv é shutil.move(). A diferença é que os.rename()não funciona se a origem e o destino estiverem em discos diferentes, enquanto shutil.move()não se importa em que disco os arquivos estão.

Jim Calfas
fonte
75
shutil.move()usa os.rename()se o destino estiver no sistema de arquivos atual. Caso contrário, shutil.move()copia a fonte para o destino usando shutil.copy2()e remove a fonte.
line break
8
Tome cuidado para perceber que shutil.copy2()não é possível copiar todos os metadados do arquivo ; portanto, se isso acontece, é como fazer cp -pe rm, então , eu entendo.
2rs2ts
9
Esteja ciente: shutil.move no Python 2.7.3 falhará se o destino já existir. Portanto, se isso for possível, pegue o erro ou remova manualmente o arquivo / dir e faça a movimentação.
Dana
36

Para os.rename ou shutil.move, você precisará importar o módulo. Nenhum caractere * é necessário para mover todos os arquivos.

Temos uma pasta em / opt / awesome chamada source com um arquivo chamado 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 o os.listdir para ver que o nome da pasta realmente mudou. Aqui está o obturador movendo o destino de volta à fonte.

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

Desta vez, verifiquei dentro da pasta de origem para ter certeza de que o arquivo awesome.txt que criei existe. Está aí :)

Agora, movemos uma pasta e seus arquivos de uma origem para um destino e voltamos novamente.

jmontross
fonte
4
docs.python.org/2/library/shutil.html Esta documentação mostra que você alterou seus parâmetros para o método shutil.move.
#
1
Eu usei o destino e a fonte invertidos para ver que os arquivos foram movidos da fonte e depois retornados a ela ... Eu pude ver como isso não está claro.
Jmontross
34

Após o Python 3.4, você também pode usar pathliba classe de Pathpara mover o arquivo.

from pathlib import Path

Path("path/to/current/file.foo").rename("path/to/new/destination/for/file.foo")

https://docs.python.org/3.4/library/pathlib.html#pathlib.Path.rename

MoonFruit
fonte
3
Importar "do pathlib import Path" funciona bem :)
Touhid 08/07/19
14

É isso que estou usando no 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)

Agora totalmente funcional. Espero que isso ajude você.

Editar:

Transformei isso em uma função, que aceita um diretório de origem e destino, criando a pasta de destino, se não existir, e move os arquivos. Também permite a filtragem dos arquivos src, por exemplo, se você deseja apenas mover imagens, então usa o padrão '*.jpg', por padrão, ele move tudo no diretório

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
fonte
1
Você pode facilmente transformar isso em um movimento filtrado usando fnmatch.filter (), veja minha edição. Além disso, o seu melhor para usar os.path.join(parent_path, filename)em vez de concatenação para evitar problemas de plataforma cruzada
iggy12345
11

A resposta aceita não é a correta, porque a questão não é renomear um arquivo para um arquivo, mas mover muitos arquivos para um diretório. shutil.movefará o trabalho, mas para esse propósito os.renameé inútil (conforme declarado nos comentários) porque o destino deve ter um nome de arquivo explícito.

Javier Palacios
fonte
Não é inútil, simplesmente requer mais trabalho para que ele mova vários arquivos. Você pode obter nomes de arquivos os.path.basename(my_file_path)e diretórios de arquivos os.path.dirname(my_file_path). Além disso, o OP não ficou muito claro se ele queria mover vários arquivos. Ele mencionou mover apenas um arquivo na pergunta, mas seu código de exemplo implicava mover vários arquivos.
Jacques Mathieu
2

Com base na resposta descrita aqui , usar subprocessé outra opção.

Algo assim:

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

Estou curioso para saber os prós e contras deste método em comparação com shutil. Como no meu caso, já estou usando subprocesspor outros motivos e parece funcionar, estou inclinado a segui-lo.

Talvez seja dependente do sistema?

Conta
fonte
2
Eu acredito que isso seria dependente do sistema. Não vejo mvsendo usado com sucesso em um sistema operacional Windows.
Joshua Schlichting em
0

Esta é uma solução que não permite o 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
fonte
-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 ex. C: -> D:

Ned Slark
fonte
se você estiver usando Python3. #, poderá usar a nova intrerpolação de string f: f"{new_path}{f}"mas, como você não possui texto estático na string, pode ser mais trabalhoso ... Estou tentando adquirir o hábito de usar f-strings embora.
jusopi
Você quer dizer arquivo em vez de f?
Matthew