Jak przenieść plik?

907

Zajrzałem do osinterfejsu Pythona , ale nie byłem w stanie znaleźć metody przeniesienia pliku. Jak mam zrobić odpowiednik $ mv ...w Pythonie?

>>> source_files = '/PATH/TO/FOLDER/*'
>>> destination_folder = 'PATH/TO/FOLDER'
>>> # equivalent of $ mv source_files destination_folder
David542
źródło
1
Dla tych z Was zna GNU Coreutils' mvpolecenia , Python shutil.movema jeden przypadek krawędzi, gdzie shutil.moveróżni funkcyjnych. Idź tutaj, aby napisać cały tekst . W skrócie, Python shutil.movezgłosi wyjątek (ale gnu-coreutils mvtego nie zrobi), gdy miejscem docelowym jest katalog, a katalog ma już plik o tej samej nazwie co źródło (ponownie, aby uzyskać więcej informacji, zobacz link podany w poprzednim zdaniu ).
Trevor Boyd Smith
3
Jak o os.system("mv file1 file2")?
John Strood

Odpowiedzi:

1337

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

Wszystkie stosują tę samą składnię:

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

Pamiętaj, że musisz podać nazwę pliku ( file.foo) zarówno w argumentach źródłowym, jak i docelowym. Jeśli zostanie zmieniony, nazwa pliku zostanie zmieniona, a także przeniesiona.

Zauważ również, że w pierwszych dwóch przypadkach katalog, w którym tworzony jest nowy plik, musi już istnieć. W systemie Windows plik o tej nazwie nie może istnieć lub zostanie zgłoszony wyjątek, ale os.replace()po cichu zastąpi plik nawet w takim przypadku.

Jak zauważono w komentarzach do innych odpowiedzi, w większości przypadków shutil.movepo prostu dzwoni os.rename. Jeśli jednak miejsce docelowe znajduje się na innym dysku niż źródło, skopiuje, a następnie usunie plik źródłowy.

ig0774
źródło
8
Czy jestem jedynym, który uważa, że ​​os.rename nie działa dla katalogów? Cytuję: „Jeśli dst jest katalogiem, podniesiony zostanie błąd OSError”.
Fabian
33
shutil.movedziała dla katalogów. Możesz użyć ścieżki względnej shutil.move(f.name, "tmp/")lub pełnej shutil.move(f.name, "/Users/hello/tmp/"), nie używaj jej ~ na ścieżce, zaznaczone w python2.7.9, Mac OS X.
dlaczegoisyoung 21.04.15
3
~jest konstrukcją powłoki i nie ma nic wspólnego ze ścieżkami plików jako takimi, jak złą konwencją. Jeśli naprawdę chcesz zaangażować swój katalog domowy, użyj os.getenv('HOME')zamiast tego, łącząc go z częściami pożądanej ścieżki, jeśli to konieczne.
AMN
15
Zawsze możesz użyć, os.path.expanduser()aby poprawnie rozwinąć „ ~” zgodnie z regułami specyficznymi dla systemu operacyjnego. Znacznie fajniejsze, ponieważ %HOME%nie zawsze jest ustawione w systemie Windows.
ig0774
14
os.renamenie obsługuje plików na różnych urządzeniach. Użyj, shutil.movejeśli nie masz pewności, czy plik źródłowy i docelowy znajdują się na tym samym urządzeniu.
Giuseppe Scrivano
244

Mimo os.rename()i shutil.move()oba będą zmieniać nazwy plików, najbliższe jest polecenie Univ mv shutil.move(). Różnica polega na tym, os.rename()że nie działa, jeśli źródło i miejsce docelowe znajdują się na różnych dyskach, a shutil.move()nie obchodzi, na jakim dysku znajdują się pliki.

Jim Calfas
źródło
75
shutil.move()używa, os.rename()jeśli miejsce docelowe znajduje się w bieżącym systemie plików. W przeciwnym razie shutil.move()kopiuje źródło do miejsca docelowego za pomocą, shutil.copy2()a następnie usuwa źródło.
przerwa w linii
8
Uważaj, aby zdać sobie sprawę, że shutil.copy2()nie można skopiować wszystkich metadanych pliku , więc jeśli tak się stanie, to tak, jakby to zrobić, cp -pa następnie rm, jak się okazuje,
2rs2ts
9
Pamiętaj: shutil.move w Pythonie 2.7.3 kończy się niepowodzeniem, jeśli miejsce docelowe już istnieje. Jeśli to możliwe, albo złap błąd, albo ręcznie usuń plik / katalog, a następnie wykonaj ruch.
Dana
36

W przypadku nazwy os.rename lub shutil.move musisz zaimportować moduł. Do przeniesienia wszystkich plików nie jest wymagany znak *.

Mamy folder w / opt / awesome o nazwie source z jednym plikiem o nazwie 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']

Użyliśmy os.listdir, aby zobaczyć, że nazwa folderu faktycznie się zmieniła. Oto shutil przenoszący cel z powrotem do źródła.

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

Tym razem sprawdziłem w folderze źródłowym, aby upewnić się, że utworzony plik awesome.txt istnieje. Jest tam :)

Teraz przenieśliśmy folder i jego pliki ze źródła do miejsca docelowego iz powrotem.

jmontross
źródło
4
docs.python.org/2/library/shutil.html Ta dokumentacja pokazuje, że zmieniłeś parametry dla metody shutil.move.
mac10688
1
Użyłem odwróconego miejsca docelowego i źródła, aby zobaczyć, że pliki zostały przeniesione ze źródła, a następnie z powrotem do niego .... Widziałem, jak to jest niejasne.
jmontross
34

Po Pythonie 3.4 możesz także użyć pathlibklasy, Pathaby przenieść plik.

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
źródło
3
Importowanie „z importu pathlib Ścieżka” działa dobrze :)
Touhid
14

Z tego właśnie korzystam:

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)

Teraz w pełni funkcjonalny. Mam nadzieję, że to ci pomoże.

Edytować:

Przekształciłem to w funkcję, która akceptuje katalog źródłowy i docelowy, tworząc folder docelowy, jeśli nie istnieje, i przenosi pliki. Pozwala również na filtrowanie plików src, na przykład jeśli chcesz tylko przenosić obrazy, następnie używasz wzorca '*.jpg', domyślnie przenosi wszystko w katalogu

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
źródło
1
Możesz łatwo zmienić to w filtrowany ruch za pomocą fnmatch.filter (), zobacz moją edycję. Ponadto najlepiej jest używać os.path.join(parent_path, filename)zamiast konkatenacji łańcuchów, aby uniknąć problemów międzyplatformowych
iggy12345
11

Przyjęta odpowiedź nie jest prawidłowa, ponieważ pytanie nie dotyczy zmiany nazwy pliku na plik, ale przeniesienie wielu plików do katalogu. shutil.movewykona pracę, ale w tym celu os.renamejest bezużyteczny (jak podano w komentarzach), ponieważ miejsce docelowe musi mieć jawną nazwę pliku.

Javier Palacios
źródło
Nie jest to bezużyteczne, po prostu wymaga więcej pracy, aby przenieść wiele plików. Możesz uzyskać nazwy plików os.path.basename(my_file_path)i katalogi plików za pomocą os.path.dirname(my_file_path). Ponadto OP nie wyjaśnił, czy chce przenieść wiele plików. Wspomniał o przeniesieniu tylko jednego pliku w pytaniu, ale jego przykładowy kod sugerował przeniesienie wielu plików.
Jacques Mathieu
2

W oparciu o opisaną tutaj odpowiedź użycie subprocessto kolejna opcja.

Coś takiego:

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

Jestem ciekawy, jakie są zalety i wady tej metody w porównaniu do shutil. Ponieważ w moim przypadku używam już subprocessz innych powodów i wydaje się, że działa, jestem skłonny się z tym trzymać.

Czy może zależy to od systemu?

Rachunek
źródło
2
Wierzę, że byłoby to zależne od systemu. Nie widzę, aby mvbył używany z powodzeniem w systemie operacyjnym Windows.
Joshua Schlichting
0

Jest to rozwiązanie, które nie umożliwia shellkorzystania 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
źródło
-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 

inny dysk np. C: -> D:

Ned Slark
źródło
jeśli używasz Python3. # możesz użyć nowej interpolacji ciągów f: f"{new_path}{f}"ale biorąc pod uwagę, że nie masz statycznego tekstu w ciągu, może to być więcej pracy ... Próbowałem przyzwyczaić się do używania f-stringi.
jusopi
Masz na myśli plik zamiast f?
Matthew