จะย้ายไฟล์ได้อย่างไร?


909

ฉันค้นหาในosอินเทอร์เฟซPython แต่ไม่พบวิธีการย้ายไฟล์ ฉันจะทำสิ่งที่เทียบเท่า$ mv ...ใน Python ได้อย่างไร?

>>> source_files = '/PATH/TO/FOLDER/*'
>>> destination_folder = 'PATH/TO/FOLDER'
>>> # equivalent of $ mv source_files destination_folder

1
สำหรับคนที่คุณคุ้นเคยกับคำสั่งของ gnu-coreutilsmv python shutil.moveมีเคสแบบขอบหนึ่งอันที่shutil.moveฟังก์ชันแตกต่างกัน ไปที่นี่สำหรับเต็มเขียนขึ้น โดยสรุป Python shutil.moveจะยกข้อยกเว้น (แต่ gnu-coreutils mvจะไม่)เมื่อปลายทางของคุณเป็นไดเรกทอรีและไดเรกทอรีมีไฟล์ที่มีชื่อเดียวกับแหล่งที่มา (อีกครั้งสำหรับข้อมูลเพิ่มเติมดูลิงค์ที่ให้ไว้ในประโยคก่อนหน้า )
เทรเวอร์บอยด์สมิ ธ

3
แล้วไงos.system("mv file1 file2")ล่ะ
John Strood

คำตอบ:


1340

os.rename(), shutil.move()หรือos.replace()

ทั้งหมดใช้ไวยากรณ์เดียวกัน:

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

โปรดทราบว่าคุณต้องรวมชื่อไฟล์ ( file.foo) ในทั้งอาร์กิวเมนต์ต้นทางและปลายทาง หากมีการเปลี่ยนแปลงไฟล์จะถูกเปลี่ยนชื่อเช่นเดียวกับการย้าย

โปรดทราบว่าในสองกรณีแรกไดเรกทอรีที่ไฟล์ใหม่จะถูกสร้างจะต้องมีอยู่แล้ว บน Windows ไฟล์ที่มีชื่อนั้นจะต้องไม่มีอยู่จริงหรือจะมีข้อยกเว้นเกิดขึ้น แต่os.replace()จะแทนที่ไฟล์อย่างเงียบ ๆ แม้จะอยู่ในเหตุการณ์นั้น

ตามที่ได้รับการบันทึกไว้ในความคิดเห็นเกี่ยวกับคำตอบอื่น ๆshutil.moveเพียงโทรos.renameในกรณีส่วนใหญ่ อย่างไรก็ตามหากปลายทางอยู่ในดิสก์ที่แตกต่างจากแหล่งที่มามันจะคัดลอกแล้วลบไฟล์ต้นฉบับ


8
ฉันเป็นคนเดียวที่คิดว่า os.rename ไม่ทำงานกับไดเรกทอรีหรือไม่ ฉันพูด: "ถ้า dst เป็นไดเรกทอรี OSError จะถูกยกขึ้น"
เฟเบียน

33
shutil.moveใช้งานได้กับไดเรกทอรี คุณสามารถใช้เส้นทางสัมพันธ์shutil.move(f.name, "tmp/")หรือเส้นทางแบบเต็ม shutil.move(f.name, "/Users/hello/tmp/"), ไม่ได้ใช้ ~ในเส้นทางการตรวจสอบใน python2.7.9, Mac OS X ได้
whyisyoung

3
~เป็นโครงสร้างของเชลล์และไม่มีส่วนเกี่ยวข้องกับพา ธ ไฟล์ต่อ se นอกเหนือจากการวางผิดตำแหน่ง หากคุณต้องการที่จะมีส่วนร่วมในไดเรกทอรีบ้านของคุณจริงๆให้ใช้os.getenv('HOME')แทนเชื่อมต่อกับส่วนของเส้นทางที่คุณต้องการหากจำเป็น
พฤศจิกายน

15
คุณสามารถใช้os.path.expanduser()เพื่อขยาย ' ~' ตามกฎเฉพาะระบบปฏิบัติการได้อย่างถูกต้อง มีผู้เข้าชมมากมายเนื่องจาก%HOME%ไม่ได้ติดตั้งบน Windows เสมอ
ig0774

14
os.renameจะไม่จัดการไฟล์ข้ามอุปกรณ์ต่าง ๆ ใช้shutil.moveหากคุณไม่แน่ใจว่าแหล่งที่มาและไฟล์ปลายทางอยู่ในอุปกรณ์เดียวกัน
Giuseppe Scrivano

244

แม้ว่าos.rename()และshutil.move()จะเปลี่ยนชื่อไฟล์ทั้งสองคำสั่งที่ใกล้เคียงกับยูนิกซ์ mv shutil.move()คำสั่ง ความแตกต่างคือos.rename()ไม่ได้ผลถ้าแหล่งที่มาและปลายทางอยู่บนดิสก์ที่แตกต่างกันในขณะที่shutil.move()ไม่สนใจว่าไฟล์อยู่ในดิสก์ใด


75
shutil.move()ใช้os.rename()ถ้าปลายทางอยู่บนระบบไฟล์ปัจจุบัน มิฉะนั้นให้shutil.move()คัดลอกต้นทางไปยังปลายทางโดยใช้shutil.copy2()แล้วลบแหล่งที่มา
ตัวแบ่งบรรทัด

8
ระวังให้ดีว่าshutil.copy2()ไม่สามารถคัดลอกข้อมูลเมตาของไฟล์ทั้งหมดได้ดังนั้นถ้าเกิดว่ามันเป็นเช่นcp -pนั้นrmฉันก็รวบรวม
2rs2ts

9
ระวัง: shutil.move ใน Python 2.7.3 ล้มเหลวหากปลายทางมีอยู่แล้ว ดังนั้นหากเป็นไปได้ให้ตรวจจับข้อผิดพลาดหรือลบไฟล์ / dir ด้วยตนเองจากนั้นทำการย้าย
Dana

36

สำหรับ os.rename หรือ shutil.move คุณจะต้องนำเข้าโมดูล ไม่จำเป็นต้องใช้อักขระ * เพื่อย้ายไฟล์ทั้งหมด

เรามีโฟลเดอร์ที่ / opt / Awesome ที่เรียกว่าแหล่งที่มาพร้อมกับหนึ่งไฟล์ชื่อ 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']

เราใช้ os.listdir เพื่อดูว่าชื่อโฟลเดอร์นั้นเปลี่ยนไป นี่คือ shutil ที่ย้ายปลายทางกลับไปยังแหล่งที่มา

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

ครั้งนี้ฉันตรวจสอบภายในโฟลเดอร์ซอร์สเพื่อให้แน่ใจว่ามีไฟล์ Awesome.txt ที่ฉันสร้างขึ้น มันอยู่ที่นั่น :)

ตอนนี้เราได้ย้ายโฟลเดอร์และไฟล์จากแหล่งไปยังปลายทางแล้วกลับมาอีกครั้ง


4
docs.python.org/2/library/shutil.htmlเอกสารนี้แสดงให้เห็นว่าคุณได้เปลี่ยนพารามิเตอร์ของคุณเป็นเมธอด shutil.move
mac10688

1
ฉันใช้ปลายทางและที่มากลับด้านเพื่อดูว่าไฟล์ถูกย้ายจากแหล่งที่มาแล้วกลับไปที่ .... ฉันสามารถดูว่ามันไม่ชัดเจน
jmontross

34

หลังจาก Python 3.4 คุณสามารถใช้pathlibคลาสPathเพื่อย้ายไฟล์ได้

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


3
วิธีการนำเข้า "จาก pathlib การนำเข้า Path" ใช้งานได้ดี :)
23445

14

นี่คือสิ่งที่ฉันใช้ในขณะนี้:

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)

ตอนนี้ทำงานได้อย่างสมบูรณ์ หวังว่านี่จะช่วยคุณได้

แก้ไข:

ฉันได้เปลี่ยนสิ่งนี้เป็นฟังก์ชั่นที่ยอมรับไดเรกทอรีต้นทางและปลายทางทำให้โฟลเดอร์ปลายทางหากไม่มีอยู่และย้ายไฟล์ อนุญาตให้กรองไฟล์ src เช่นถ้าคุณต้องการย้ายรูปภาพเท่านั้นจากนั้นคุณใช้รูปแบบ'*.jpg'ตามค่าเริ่มต้นมันจะย้ายทุกอย่างในไดเรกทอรี

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

1
คุณสามารถทำให้สิ่งนี้กลายเป็นการย้ายที่ถูกกรองได้อย่างง่ายดายโดยใช้ fnmatch.filter () ดูการแก้ไขของฉัน นอกจากนี้ยังใช้งานได้ดีที่สุดos.path.join(parent_path, filename)แทนที่จะใช้การเรียงสตริงเพื่อหลีกเลี่ยงปัญหาข้ามแพลตฟอร์ม
iggy12345

11

คำตอบที่ยอมรับไม่ใช่คำตอบที่ถูกต้องเพราะคำถามไม่ได้เกี่ยวกับการเปลี่ยนชื่อไฟล์เป็นไฟล์ แต่ย้ายไฟล์จำนวนมากไปยังไดเรกทอรี shutil.moveจะทำงาน แต่สำหรับวัตถุประสงค์os.renameนี้ไร้ประโยชน์ (ตามที่ระบุไว้ในความคิดเห็น) เพราะปลายทางจะต้องมีชื่อไฟล์ที่ชัดเจน


ไม่ไร้ประโยชน์เพียงแค่ต้องการงานมากขึ้นเพื่อย้ายไฟล์หลายไฟล์ คุณจะได้รับชื่อไฟล์ที่มีและไดเรกทอรีไฟล์ด้วยos.path.basename(my_file_path) os.path.dirname(my_file_path)นอกจากนี้มันไม่ได้ทำให้ชัดเจนโดย OP ถ้าเขาต้องการย้ายหลายไฟล์ เขากล่าวถึงการย้ายเพียงหนึ่งไฟล์ในคำถาม แต่โค้ดตัวอย่างของเขาบอกเป็นนัยถึงการย้ายหลายไฟล์
Jacques Mathieu

2

ตามคำตอบที่อธิบายไว้ที่นี่การใช้subprocessเป็นตัวเลือกอื่น

บางสิ่งเช่นนี้

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

shutilผมอยากที่จะรู้ว่าโปรและของนักโทษของวิธีการนี้เมื่อเทียบกับ เนื่องจากในกรณีของฉันฉันใช้อยู่แล้วsubprocessด้วยเหตุผลอื่นและดูเหมือนว่าจะทำงานฉันมีแนวโน้มที่จะยึดติดอยู่กับมัน

มันขึ้นอยู่กับระบบอาจจะ?


2
ฉันเชื่อว่านี่จะขึ้นอยู่กับระบบ ฉันไม่เห็นmvการใช้งานสำเร็จบนระบบปฏิบัติการ windows
Joshua Schlichting

0

นี่เป็นวิธีแก้ปัญหาซึ่งไม่สามารถshellใช้งาน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

-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 

ดิสก์ที่แตกต่างกัน C: -> D:


ถ้าคุณกำลังใช้ Python3 # คุณสามารถใช้การเพิ่มสตริง f-string ใหม่: f"{new_path}{f}"แต่เนื่องจากคุณไม่มีข้อความคงที่ในสตริงของคุณสิ่งนี้อาจทำงานได้มากกว่านี้ .... ฉันพยายามทำให้เป็นนิสัยในการใช้งาน แม้ว่าสตริง -f
jusopi

คุณหมายถึงไฟล์แทน f หรือเปล่า?
Matthew
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.