Python Forum

Full Version: Improving code to autorename if filename exists
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi all, I have a part of my code that I would like to give a little upgrade.
import os
import shutil

dest = '/path/to/dest_folder'
src = '/path/to/src_folder'

for root, subdirs, files in os.walk(src):
    for file in files:
        path = os.path.join(root, file)
        shutil.move(path, dest)
This code replaces files from a folder and its subfolders to one destination-folder. The problem here is: If there are 2 files with thesame filename I get an error:
Quote:shutil.Error: Destination path '/path/to/dest_folder/filename' already exists

I'd like to change this code so it automaticly renames the file if it already exists in the destination-folder because thesame filename doesn't mean it has thesame content so I don't want to overwrite files in the destination-folder.

I've been thinking about using a timestamp but I'm not sure If and how to do it. Any tips? Ideas?

Thanks :)
Hello!
Just catch the error.
for root, subdirs, files in os.walk(src):
    for file in files:
        path = os.path.join(root, file)
        try:
            shutil.move(path, dest)
        except shutil.Error:
            #rename the file
You can look at the datetime module if you want to do things with, well, dates and times.
Browsers or other downloading programs often have the strategy to create filename-1.txt, filename-2.txt, ... if filename.txt already exists. Here is a way to generate them
import itertools as itt
import os
import re

def altnames(filename):
    """Generate a sequence of alternate names for a filename.
    
    The first name generated is filename itself.
    """
    yield filename
    stem, ext = os.path.splitext(filename)
    match = re.search(r'\-(\d+)$', stem)
    if match:
        n = int(match.group(1))
        s = stem[:match.start()]
    else:
        n = 0
        s = stem
    for i in itt.count(n+1):
        yield '{}-{}{}'.format(s, i, ext)
        
if __name__ == '__main__':
    for f in ['ham.py', 'spam-122.txt', 'eggs-11-13.pdf']:
        for n in itt.islice(altnames(f), 3):
            print(n)
Result:
Output:
ham.py ham-1.py ham-2.py spam-122.txt spam-123.txt spam-124.txt eggs-11-13.pdf eggs-11-14.pdf eggs-11-15.pdf
(Sep-22-2019, 07:10 AM)wavic Wrote: [ -> ]Hello!
Just catch the error.
for root, subdirs, files in os.walk(src):
    for file in files:
        path = os.path.join(root, file)
        try:
            shutil.move(path, dest)
        except shutil.Error:
            #rename the file

Hi, thisone looks like it's the easiest solution. I did a lot of research on renaming the file but I didn't really figure it out yet (with my pretty basic knowledge). Do you have any suggestions about how I should rename the file?

(Sep-22-2019, 09:50 AM)Gribouillis Wrote: [ -> ]Browsers or other downloading programs often have the strategy to create filename-1.txt, filename-2.txt, ... if filename.txt already exists. Here is a way to generate them
import itertools as itt
import os
import re

def altnames(filename):
    """Generate a sequence of alternate names for a filename.
    
    The first name generated is filename itself.
    """
    yield filename
    stem, ext = os.path.splitext(filename)
    match = re.search(r'\-(\d+)$', stem)
    if match:
        n = int(match.group(1))
        s = stem[:match.start()]
    else:
        n = 0
        s = stem
    for i in itt.count(n+1):
        yield '{}-{}{}'.format(s, i, ext)
        
if __name__ == '__main__':
    for f in ['ham.py', 'spam-122.txt', 'eggs-11-13.pdf']:
        for n in itt.islice(altnames(f), 3):
            print(n)
Result:
Output:
ham.py ham-1.py ham-2.py spam-122.txt spam-123.txt spam-124.txt eggs-11-13.pdf eggs-11-14.pdf eggs-11-15.pdf

This looks really interesting but with my basic python-knowledge difficult to understand or to figure out how I should implement this in my own code. But thank you anyways! :)
If you have file 'file.txt' ou can rename it 'file(1).txt' for example - as browsers do. Or without the brackets if you like it more.