【问题标题】:How to move a file in Python?如何在 Python 中移动文件?
【发布时间】:2020-03-05 18:50:07
【问题描述】:

我查看了 Python os 接口,但找不到移动文件的方法。我将如何在 Python 中执行相当于 $ mv ... 的操作?

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

【问题讨论】:

  • 对于那些熟悉gnu-coreutils' mv command 的人来说,python 的shutil.move 有一个极端情况,其中shutil.move 函数不同。 Go here for full write up简而言之,Python 的 shutil.move 将引发异常(但 gnu-coreutils mv 不会) 当您的目标是一个目录并且该目录已经有一个与源同名的文件时(有关更多信息,请参阅上一句中提供的链接)。
  • os.system("mv file1 file2") 怎么样?

标签: python file file-handling python-os


【解决方案1】:

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

都使用相同的语法:

import os
import shutil

os.rename("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")
shutil.move("path/to/current/file.foo", "path/to/new/destination/for/file.foo")

请注意,您必须在源参数和目标参数中都包含文件名 (file.foo)。如果更改,文件将被重命名和移动。

还要注意,在前两种情况下,创建新文件的目录必须已经存在。在 Windows 上,不得存在具有该名称的文件,否则将引发异常,但 os.replace() 将静默替换文件,即使在这种情况下。

正如 cmets 在其他答案中所指出的,shutil.move 在大多数情况下只是调用os.rename。但是,如果目标位于与源不同的磁盘上,它将改为复制然后删除源文件。

【讨论】:

  • 我是唯一认为 os.rename 不适用于目录的人吗?我引用:“如果 dst 是一个目录,则会引发 OSError。”
  • shutil.move 适用于目录。可以使用相对路径shutil.move(f.name, "tmp/")或者完整路径shutil.move(f.name, "/Users/hello/tmp/"),路径中不要使用 ~,在python2.7.9,Mac OS X中勾选。
  • ~ 是一个 shell 结构,与文件路径本身无关,只是作为一个错误的约定。如果您真的想涉及您的主目录,请改用os.getenv('HOME'),如有必要,将其与您想要的路径的一部分连接起来。
  • 您始终可以使用os.path.expanduser() 根据操作系统特定的规则正确扩展“~”。因为%HOME% 并不总是在 Windows 上设置,所以更加整洁。
  • os.rename 不会跨不同设备处理文件。如果您不确定源文件和目标文件是否在同一设备上,请使用 shutil.move
【解决方案2】:

虽然os.rename()shutil.move() 都会重命名文件,但最接近Unix mv 命令的命令是shutil.move()。不同之处在于,如果源和目标位于不同的磁盘上,os.rename() 将不起作用,而 shutil.move() 与文件磁盘无关。

【讨论】:

  • shutil.move() 如果目标位于当前文件系统上,则使用 os.rename()。否则,shutil.move() 使用 shutil.copy2() 将源复制到目标,然后删除源。
  • 请注意shutil.copy2() can't copy all file metadata,所以如果发生这种情况,就像先做cp -p,然后再做rm,我收集。
  • 注意:如果目标已经存在,Python 2.7.3 中的 shutil.move 会失败。因此,如果可能的话,要么捕获错误,要么手动删除文件/目录,然后进行移动。
【解决方案3】:

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

【讨论】:

  • 我最近以 --> Path("path/to/current/file.foo").rename("path/to/new/destination/for/".joinpath(Path.name)) 的形式使用它来将所有 *.LNK(快捷方式)文件移动到 DUMP 目录。像魅力一样工作! :D
  • 这很好用,但如果你想将文件从一台设备移动到另一台设备就会失败(跨设备链接无效)
  • @Amar 也许这样更好。 Path("path/to/current/file.foo").rename(Path("path/to/new/destination/for") / Path.name))
【解决方案4】:

对于 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 来查看文件夹名称实际上发生了变化。 这是将目的地移回源头的shutil。

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

这次我检查了源文件夹,以确保我创建的 awesome.txt 文件存在。它在那里:)

现在我们已将文件夹及其文件从源移动到目标并再次返回。

【讨论】:

  • docs.python.org/2/library/shutil.html 该文档显示您已为 shutil.move 方法切换了参数。
  • 我使用目标和源反转来查看文件从源移动然后返回到它......我可以看到这是不清楚的。
【解决方案5】:

这是我目前正在使用的:

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

【讨论】:

  • 您可以使用 fnmatch.filter() 轻松地将其转换为过滤移动,请参阅我的编辑。此外,最好使用os.path.join(parent_path, filename) 而不是字符串连接以避免跨平台问题
【解决方案6】:

公认的答案不是正确的,因为问题不在于将文件重命名为文件,而是将许多文件移动到目录中。 shutil.move 将完成这项工作,但为此目的 os.rename 是无用的(如 cmets 所述),因为目标必须具有明确的文件名。

【讨论】:

  • 不是没用,只是需要更多的工作才能让它移动多个文件。您可以使用os.path.basename(my_file_path) 获取文件名,使用os.path.dirname(my_file_path) 获取文件目录。此外,如果他想移动多个文件,OP 并没有说得很清楚。他在问题中提到只移动一个文件,但他的示例代码暗示移动多个文件。
【解决方案7】:

也可以使用subprocess.run() 方法。

python:
>>> import subprocess
>>> new = "/path/to/destination"
>>> old = "/path/to/new/destination"
>>> process = "mv ..{} ..{}".format(old,new)
>>> subprocess.run(process, shell=True) # do not remember, assign shell value to True.

这在 Linux 上工作时可以正常工作。由于没有 mv 命令,Windows 可能会出错。

【讨论】:

  • 当python有API时为什么要调用外部进程?
【解决方案8】:

基于答案described here,使用subprocess 是另一种选择。

类似这样的:

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

我很想知道这种方法与shutil 相比的优缺点。因为在我的情况下,我已经出于其他原因使用subprocess,而且它似乎有效,我倾向于坚持使用它。

这取决于您在其中运行脚本的 shell。mv 命令适用于大多数 Linux shell(bash、sh 等),但也适用于 Windows 上的 Git Bash 等终端。对于其他终端,您必须将 mv 更改为备用命令。

【讨论】:

  • 我相信这将取决于系统。我没有看到 mv 在 Windows 操作系统上成功使用。
  • @JoshuaSchlichting 它会比平台类型更依赖于 shell。例如,在 Windows 上,这将在 Git Bash 终端中正常工作,但不能使用 Cmd。
  • @LightCC 好收获!谢谢!
  • 我在最后一段中用正确的信息更新了答案,而不是系统相关的问题。
【解决方案9】:

这是一个解决方案,它不能使用mv 启用shell

from subprocess import Popen, PIPE, STDOUT

source = "path/to/current/file.foo", 
destination = "path/to/new/destination/for/file.foo"

p = Popen(["mv", "-v", source, destination], stdout=PIPE, stderr=STDOUT)
output, _ = p.communicate()
output = output.strip().decode("utf-8")
if p.returncode:
    print(f"E: {output}")
else:
    print(output)

【讨论】:

    【解决方案10】:
      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-strings 的习惯。
    • 你的意思是file而不是f?
    猜你喜欢
    • 2022-11-13
    • 1970-01-01
    • 2012-01-24
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多