How to move a file in Python?

1,433,585

Solution 1

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

All employ the same syntax:

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

Note that you must include the file name (file.foo) in both the source and destination arguments. If it is changed, the file will be renamed as well as moved.

Note also that in the first two cases the directory in which the new file is being created must already exist. On Windows, a file with that name must not exist or an exception will be raised, but os.replace() will silently replace a file even in that occurrence.

As has been noted in comments on other answers, shutil.move simply calls os.rename in most cases. However, if the destination is on a different disk than the source, it will instead copy and then delete the source file.

Solution 2

Although os.rename() and shutil.move() will both rename files, the command that is closest to the Unix mv command is shutil.move(). The difference is that os.rename() doesn't work if the source and destination are on different disks, while shutil.move() is files disk agnostic.

Solution 3

After Python 3.4, you can also use pathlib's class Path to move file.

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

Solution 4

For either the os.rename or shutil.move you will need to import the module. No * character is necessary to get all the files moved.

We have a folder at /opt/awesome called source with one file named 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']

We used os.listdir to see that the folder name in fact changed. Here's the shutil moving the destination back to source.

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

This time I checked inside the source folder to be sure the awesome.txt file I created exists. It is there :)

Now we have moved a folder and its files from a source to a destination and back again.

Solution 5

This is what I'm using at the moment:

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)

Now fully functional. Hope this helps you.

Edit:

I've turned this into a function, that accepts a source and destination directory, making the destination folder if it doesn't exist, and moves the files. Also allows for filtering of the src files, for example if you only want to move images, then you use the pattern '*.jpg', by default, it moves everything in the directory

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))
Share:
1,433,585
David542
Author by

David542

Updated on January 06, 2022

Comments

  • David542
    David542 over 2 years

    I looked into the Python os interface, but was unable to locate a method to move a file. How would I do the equivalent of $ mv ... in Python?

    >>> source_files = '/PATH/TO/FOLDER/*'
    >>> destination_folder = 'PATH/TO/FOLDER'
    >>> # equivalent of $ mv source_files destination_folder
    
  • mac10688
    mac10688 about 11 years
    docs.python.org/2/library/shutil.html This documentation shows that you have you your parameters switched for the shutil.move method.
  • jmontross
    jmontross about 11 years
    I used the destination and source reversed to see that the files moved from the source and then back to it.... I could see how that is unclear.
  • fmalina
    fmalina over 10 years
    shutil.move() uses os.rename() if the destination is on the current filesystem. Otherwise, shutil.move() copies the source to destination using shutil.copy2() and then removes the source.
  • 2rs2ts
    2rs2ts about 10 years
    Take care to realize that shutil.copy2() can't copy all file metadata, so if that happens it's like doing cp -p and then rm, I gather.
  • Dana
    Dana almost 10 years
    Be aware: shutil.move in Python 2.7.3 fails if the destination already exists. So if that is possible, either catch the error, or manually remove the file/dir, then do the move.
  • Fabian
    Fabian almost 10 years
    Am I the only one that thinks os.rename is not working for directories? I quote: "If dst is a directory, OSError will be raised."
  • whyisyoung
    whyisyoung about 9 years
    shutil.move works for directories. You can use relative path shutil.move(f.name, "tmp/") or full path shutil.move(f.name, "/Users/hello/tmp/"), do not use ~ in the path, checked in python2.7.9, Mac OS X.
  • Armen Michaeli
    Armen Michaeli almost 9 years
    ~ is a shell construct, and has nothing to do with file paths per se, other than as a misplaced convention. If you really want to involve your home directory, use os.getenv('HOME') instead, concatenating it with parts of your desired path, if necessary.
  • ig0774
    ig0774 almost 9 years
    You could always use os.path.expanduser() to properly expand the '~' according to os-specific rules. Much neater since %HOME% isn't always set on Windows.
  • c z
    c z over 7 years
    If you want to use os then os.rename behaves differently on different platforms if the file exists, instead use os.replace
  • Giuseppe Scrivano
    Giuseppe Scrivano about 7 years
    os.rename won't handle files across different devices. Use shutil.move if you are not sure the source and the destination file are on the same device.
  • jusopi
    jusopi over 5 years
    if you are using Python3.# you can use the new f-string intrerpolation: f"{new_path}{f}" but given that you have no static text in your string, this may be more work.... I've been trying to get into the habit of using f-strings though.
  • Zachary Ryan Smith
    Zachary Ryan Smith over 5 years
    On my Mac, os.rename would err with OSError: [Errno 2] No such file or directory, even though it seemed to work fine (except for throwing the error). os.replace is undefined (python 2.7). shutil.move seems to work fine
  • Jacques Mathieu
    Jacques Mathieu about 5 years
    Not useless, simply requires more work to get it to move multiple files. You can get file names with os.path.basename(my_file_path) and the file directories with os.path.dirname(my_file_path). Additionally, it was not made very clear by the OP if he wanted to move multiple files. He mentioned moving only one file in the question, but his example code implied moving multiple files.
  • iggy12345
    iggy12345 about 5 years
    You can easily turn this into a filtered move by using fnmatch.filter(), see my edit. Also, its best to use os.path.join(parent_path, filename) instead of string concatenation to avoid cross-platform issues
  • Bachsau
    Bachsau about 5 years
    @Fabian It works with directories, but the destination can not be an existing directory. If destination is an existing file, it will be replaced. Normally destination should not exist, and if it is a directory, it will not replace that whole directory with something else. rename is a simple command with clear semantics. It does not make the assumption to place a file inside a directory if destination is a directory. But you can move whole directories with it.
  • Matthew
    Matthew over 4 years
    Do you mean file instead of f?
  • jxramos
    jxramos over 4 years
    I'd like to point out that at least for Windows running Python 3.7.3 that shutil.move respects the file attributes, both created and modified which is really great. This was a folder to folder move on the same disk. It would be really great to run those experiments for each of the commands above and tabulate the attribute preserving behavior across OS platforms and even drives by the looks of it.
  • Joshua Schlichting
    Joshua Schlichting about 4 years
    I believe this would be system dependent. I don't see mv being used successfully on a windows operating system.
  • Amar
    Amar over 3 years
    I used it recently in the form of --> Path("path/to/current/file.foo").rename("path/to/new/destina‌​tion/for/".joinpath(‌​Path.name)) to move all the *.LNK (shortcut) files to a DUMP directory. Worked like a charm! :D
  • capooti
    capooti over 3 years
    This works perfectly, but it will fail if you want move the file from one device to another (Invalid cross-device link)
  • Timo
    Timo over 3 years
    I do not think this is valid for shutil.move: Note that you must include the file name (file.foo) in both the source and destination arguments.
  • MoonFruit
    MoonFruit about 3 years
    @Amar maybe this is better. Path("path/to/current/file.foo").rename(Path("path/to/new/de‌​stination/for") / Path.name))
  • Pranav Gupta
    Pranav Gupta almost 3 years
    Why to call external process when python has API for that ?
  • LightCC
    LightCC over 2 years
    @JoshuaSchlichting It would be more shell dependent than platform type. For example, on Windows this will work fine in a Git Bash terminal, but not using Cmd.
  • Joshua Schlichting
    Joshua Schlichting over 2 years
    @LightCC Good catch! Thanks!
  • LightCC
    LightCC over 2 years
    I updated the answer with the correct information in the final paragraph rather than a question if it's system dependent.
  • Ludo Schmidt
    Ludo Schmidt about 2 years
    error in the example. src,dst is reversed !
  • Bob Kline
    Bob Kline almost 2 years
    @ig0774 When you wrote "Note also that in the first two cases the directory in which the new file is being created must already exist" I read that as implying that this is not true for the third case. That's wrong, as I found out the hard way. The destination directories must already exist for shutil.move().