如何移动文件?


907

我查看了Python os界面,但无法找到移动文件的方法。我将如何$ mv ...在Python中做相当于?

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

1
对于熟悉gnu-coreutils mv命令的用户来说,python的shutil.move一种极端情况是shutil.move功能有所不同。 去这里全文写作简而言之,shutil.movemv当目标目录是目录并且目录中已有与源文件同名的文件时,Python 将引发异常(但gnu-coreutils 不会)(有关更多信息,请参见上一句中提供的链接) )。
Trevor Boyd Smith,

3
怎么os.system("mv file1 file2")
约翰·斯特罗德

Answers:


1336

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。”
Fabian 2014年

33
shutil.move适用于目录。您可以使用相对路径shutil.move(f.name, "tmp/")或完整路径 shutil.move(f.name, "/Users/hello/tmp/")不使用 ~路径,检查在python2.7.9,Mac OS X中
whyisyoung

3
~是一个shell构造,与文件路径本身无关,除了约定错误。如果您确实要包含主目录,请改用os.getenv('HOME')它,并在必要时将其与所需路径的一部分连接起来。
2015年

15
您始终可以根据特定于操作系统的规则使用os.path.expanduser()来正确地扩展“ ~”。整洁得多,因为%HOME%并非总是在Windows上设置。
ig0774 2015年

14
os.rename不会在不同设备上处理文件。使用shutil.move,如果你不知道的源和目标文件是相同的设备上。
朱塞佩·斯克里瓦诺

243

尽管os.rename()并且shutil.move()都将重命名文件,但是最接近Unix mv命令的命令是shutil.move()。区别在于,os.rename()如果源和目标位于不同的磁盘上,则shutil.move()不起作用,而与文件所在的磁盘无关。


75
shutil.move()使用os.rename()如果目标是在当前的文件系统。否则,shutil.move()使用将源复制到目标shutil.copy2(),然后删除源。
换行

8
请注意,shutil.copy2()无法复制所有文件元数据,因此,如果发生这种情况,就像在进行cp -p然后rm收集。
2rs2ts 2014年

9
请注意:如果目标位置已存在,Python 2.7.3中的shutil.move将失败。因此,如果可能的话,要么捕获错误,要么手动删除文件/目录,然后进行移动。
达娜(Dana)

36

对于os.rename或shutil.move,您将需要导入模块。要移动所有文件,无需*字符。

我们在/ opt / awesome处有一个名为source的文件夹,其中有一个名为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来查看文件夹名称实际上已更改。这是将目标移回源的途径。

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


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文件,例如,如果您只想移动图像,则使用pattern '*.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还没有明确指出他是否要移动多个文件。他提到在问题中仅移动一个文件,但是他的示例代码隐含了移动多个文件。
雅克·马修

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字符串插入:f"{new_path}{f}"但是鉴于您的字符串中没有静态文本,这可能需要更多工作...。我一直在尝试养成使用的习惯F弦。
jusopi

您的意思是文件而不是f?
马修
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.