Create file but if name exists add number

后端 未结 14 1965
醉话见心
醉话见心 2020-12-04 18:08

Does Python have any built-in functionality to add a number to a filename if it already exists?

My idea is that it would work the way certain OS\'s work - if a file

相关标签:
14条回答
  • 2020-12-04 18:50

    I ended up writing my own simple function for this. Primitive, but gets the job done:

    def uniquify(path):
        filename, extension = os.path.splitext(path)
        counter = 1
    
        while os.path.exists(path):
            path = filename + " (" + str(counter) + ")" + extension
            counter += 1
    
        return path
    
    0 讨论(0)
  • 2020-12-04 18:54

    As of Python 3.6 [f-strings format appeared]

    A great solution is to use a function that takes 2 arguments and returns the first non-existed filename available. On the first iteration, the function tries to check if filename without any number exists. If this filename is already taken, the function tries to apply a number 0 right before the file extension. If this filename is already taken too, the function adds +1 to this number until non-existed filename will be found.

    import os
    
    def unique_filename(output_filename, file_extension):
        n = ''
        while os.path.exists(f'{output_filename}{n}{file_extension}'):
            if isinstance(n, str):
                n = -1
            n += 1
        return f'{output_filename}{n}{file_extension}'
    

    For older Python versions you can use [%-strings format]

    import os
    
    def unique_filename(output_filename, file_extension):
        n = ''
        while os.path.exists('%s%s%s' % (output_filename, n, file_extension)):
            if isinstance(n, str):
                n = -1
            n += 1
        return '%s%s%s' % (output_filename, n, file_extension)
    

    Another option is a function that takes file_path as an input argument.

    file_path will be split into file path with filename and file extension (f.e. ".jpg")

    import os
    
    def unique_filename_path(file_path):
        output_filename, file_extension = os.path.splitext(file_path)
        n = ''
        while os.path.exists(f'{output_filename}{n}{file_extension}'):
          if isinstance(n, str):
              n = -1
          n += 1
        return f'{output_filename}{n}{file_extension}'
    
    0 讨论(0)
  • 2020-12-04 18:56

    If all files being numbered isn't a problem, and you know beforehand the name of the file to be written, you could simply do:

    import os
    
    counter = 0
    filename = "file{}.pdf"
    while os.path.isfile(filename.format(counter)):
        counter += 1
    filename = filename.format(counter)
    
    0 讨论(0)
  • 2020-12-04 18:57
    import os
    
    class Renamer():
        def __init__(self, name):
            self.extension = name.split('.')[-1]
            self.name = name[:-len(self.extension)-1]
            self.filename = self.name
        def rename(self):
            i = 1
            if os.path.exists(self.filename+'.'+self.extension):
                while os.path.exists(self.filename+'.'+self.extension):
                    self.filename = '{} ({})'.format(self.name,i)
                    i += 1
            return self.filename+'.'+self.extension
    
    0 讨论(0)
  • 2020-12-04 18:59

    Since the tempfile hack A) is a hack and B) still requires a decent amount of code anyway, I went with a manual implementation. You basically need:

    1. A way to Safely create a file if and only if it does not exist (this is what the tempfile hack affords us).
    2. A generator for filenames.
    3. A wrapping function to hide the mess.

    I defined a safe_open that can be used just like open:

    def iter_incrementing_file_names(path):
        """
        Iterate incrementing file names. Start with path and add " (n)" before the
        extension, where n starts at 1 and increases.
    
        :param path: Some path
        :return: An iterator.
        """
        yield path
        prefix, ext = os.path.splitext(path)
        for i in itertools.count(start=1, step=1):
            yield prefix + ' ({0})'.format(i) + ext
    
    
    def safe_open(path, mode):
        """
        Open path, but if it already exists, add " (n)" before the extension,
        where n is the first number found such that the file does not already
        exist.
    
        Returns an open file handle. Make sure to close!
    
        :param path: Some file name.
    
        :return: Open file handle... be sure to close!
        """
        flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY
    
        if 'b' in mode and platform.system() == 'Windows':
            flags |= os.O_BINARY
    
        for filename in iter_incrementing_file_names(path):
            try:
                file_handle = os.open(filename, flags)
            except OSError as e:
                if e.errno == errno.EEXIST:
                    pass
                else:
                    raise
            else:
                return os.fdopen(file_handle, mode)
    
    # Example
    with safe_open("some_file.txt", "w") as fh:
        print("Hello", file=fh)
    
    0 讨论(0)
  • 2020-12-04 19:00

    I haven't tested this yet but it should work, iterating over possible filenames until the file in question does not exist at which point it breaks.

    def increment_filename(fn):
        fn, extension = os.path.splitext(path)
    
        n = 1
        yield fn + extension
        for n in itertools.count(start=1, step=1)
            yield '%s%d.%s' % (fn, n, extension)
    
    for filename in increment_filename(original_filename):
        if not os.isfile(filename):
            break
    
    0 讨论(0)
提交回复
热议问题