python:创建文件,但如果名称存在则添加数字

时间:2012-12-13 03:58:06

标签: python file-io operating-system

python是否有任何内置功能?我的想法是,如果将文件输出到已存在该名称的文件的目录,它将以某种操作系统的工作方式工作。即:如果“file.pdf”存在,它将创建“file2.pdf”,下次“file3.pdf”。

15 个答案:

答案 0 :(得分:10)

在某种程度上,Python在tempfile模块中内置了此功能。不幸的是,您必须使用私有全局变量tempfile._name_sequence。这意味着正式地,tempfile不保证在将来的版本中_name_sequence甚至存在 - 它是一个实现细节。 但是,无论如何你都可以使用它,这表明如何在file#.pdf指定的目录中创建/tmp形式的唯一命名文件:

import tempfile
import itertools as IT
import os

def uniquify(path, sep = ''):
    def name_sequence():
        count = IT.count()
        yield ''
        while True:
            yield '{s}{n:d}'.format(s = sep, n = next(count))
    orig = tempfile._name_sequence 
    with tempfile._once_lock:
        tempfile._name_sequence = name_sequence()
        path = os.path.normpath(path)
        dirname, basename = os.path.split(path)
        filename, ext = os.path.splitext(basename)
        fd, filename = tempfile.mkstemp(dir = dirname, prefix = filename, suffix = ext)
        tempfile._name_sequence = orig
    return filename

print(uniquify('/tmp/file.pdf'))

答案 1 :(得分:3)

我试图在我的项目中实现同样的事情,但是@ unutbu的回答似乎过于沉重。为了我的需要,我最终想出了以下代码:

import os
index = ''
while True:
    try:
        os.makedirs('../hi'+index)
        break
    except WindowsError:
        if index:
            index = '('+str(int(index[1:-1])+1)+')' # Append 1 to number in brackets
        else:
            index = '(1)'
        pass # Go and try create file again

万一有人偶然发现了这个并且需要更简单的东西。

答案 2 :(得分:2)

最近我遇到了同样的事情,这是我的方法:

import os

file_name = "file_name.txt"
if os.path.isfile(file_name):
    expand = 1
    while True:
        expand += 1
        new_file_name = file_name.split(".txt")[0] + str(expand) + ".txt"
        if os.path.isfile(new_file_name):
            continue
        else:
            file_name = new_file_name
            break

答案 3 :(得分:1)

由于临时文件黑客攻击A)是一个黑客攻击而且B)仍然需要相当数量的代码,所以我选择了手动实现。你基本上需要:

  1. Safely create a file if and only if it does not exist的一种方式(这就是tempfile为我们提供的内容)。
  2. 文件名生成器。
  3. 隐藏乱七八糟的包装功能。
  4. 我定义了一个可以像open一样使用的safe_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)
    

答案 4 :(得分:1)

如果所有被编号的文件都不成问题,并且您事先知道要写入的文件的名称,则只需执行以下操作:

import os

counter = 0
filename = "file{}.pdf"
while os.path.isfile(filename.format(counter)):
    counter += 1
filename = filename.format(counter)

答案 5 :(得分:1)

我最终为此编写了自己的简单函数。原始,但是可以完成工作:

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

答案 6 :(得分:0)

我还没有对此进行测试,但它应该可以工作,迭代可能的文件名,直到有问题的文件不存在,此时它就会中断。

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

答案 7 :(得分:0)

这对我有用。 初始文件名为0.yml,如果存在,则在满足要求之前添加一个

import os
import itertools

def increment_filename(file_name):
    fid, extension = os.path.splitext(file_name)

    yield fid + extension
    for n in itertools.count(start=1, step=1):
        new_id = int(fid) + n
        yield "%s%s" % (new_id, extension)


def get_file_path():
    target_file_path = None
    for file_name in increment_filename("0.yml"):
        file_path = os.path.join('/tmp', file_name)
        if not os.path.isfile(file_path):
            target_file_path = file_path
            break
    return target_file_path

答案 8 :(得分:0)

SELECT C.NAMEXXX AS NAMEXXX, D.NAMEXXX as NAMEXXX, R.NAMEXXX AS NAMEXXX, T.NAMEXXX AS NAMEXXX
FROM GEOCITI C
LEFT JOIN GEODEPT D ON D.PKINDEX = C.FKDEPAR
LEFT JOIN GEOREGI R ON R.PKINDEX=D.FKREGIO
LEFT JOIN GEOCOUN T ON T.PKINDEX=R.FKCOUNT

答案 9 :(得分:0)

我已经使用pathlib实现了类似的解决方案:

创建与模式path/<file-name>-\d\d.ext相匹配的文件名。也许这种解决方案可以帮助...

import pathlib
from toolz import itertoolz as itz

def file_exists_add_number(path_file_name, digits=2):

    pfn = pathlib.Path(path_file_name)
    parent = pfn.parent     # parent-dir of file
    stem = pfn.stem         # file-name w/o extension
    suffix = pfn.suffix     # NOTE: extension starts with '.' (dot)!

    try:
        # search for files ending with '-\d\d.ext'
        last_file = itz.last(parent.glob(f"{stem}-{digits * '?'}{suffix}"))
    except:
        curr_no = 1
    else:
        curr_no = int(last_file.stem[-digits:]) + 1

    # int to string and add leading zeros
    curr_no = str(last_no).zfill(digits)
    path_file_name = parent / f"{stem}-{curr_no}{suffix}"

    return str(path_file_name)

请注意:该解决方案从01开始,只会找到包含-\d\d的文件模式!

答案 10 :(得分:0)

我发现os.path.exists()条件函数完成了我所需要的。我以字典到csv的保存为例,但是对于任何文件类型,相同的逻辑都可以工作:

import os 

def smart_save(filename, dict):
    od = filename + '_' # added underscore before number for clarity

    for i in np.arange(0,500,1): # I set an arbitrary upper limit of 500
        d = od + str(i)

        if os.path.exists(d + '.csv'):
            pass

        else:
            with open(d + '.csv', 'w') as f: #or any saving operation you need
                for key in dict.keys():
                    f.write("%s,%s\n"%(key, dictionary[key]))
            break

注意:默认情况下,这会在文件名后附加一个数字(从0开始),但是很容易转移。

答案 11 :(得分:0)

自Python 3.6起[出现了f字符串格式]

一个很好的解决方案是使用一个带有2个参数并返回第一个不存在的可用文件名的函数。在第一次迭代中,该函数尝试检查没有任何数字的文件名是否存在。如果已使用此文件名,则该函数将尝试在文件扩展名之前应用数字0。如果该文件名也已被占用,则该函数会在该数字后添加+1,直到找到不存在的文件名为止。

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

对于较旧的Python版本,您可以使用[%-strings格式]

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)

另一个选项是将file_path作为输入参数的函数。

file_path将分为file path with filenamefile extension(例如“ .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}'

答案 12 :(得分:0)

假设我已经有这些文件:

enter image description here

此功能通过在扩展名之前添加_1,_2,_3等后缀来生成下一个可用的不存在的文件名(如果需要):

import os

def nextnonexistent(f):
    fnew = f
    root, ext = os.path.splitext(f)
    i = 0
    while os.path.exists(fnew):
        i += 1
        fnew = '%s_%i%s' % (root, i, ext)
    return fnew

print(nextnonexistent('foo.txt'))  # foo_3.txt
print(nextnonexistent('bar.txt'))  # bar_1.txt
print(nextnonexistent('baz.txt'))  # baz.txt

答案 13 :(得分:0)

Easy way for create new file if this name in your folder

if 'sample.xlsx' in os.listdir('testdir/'):

    i = 2
    
    while os.path.exists(f'testdir/sample ({i}).xlsx'):
        i += 1
    
    wb.save(filename=f"testdir/sample ({i}).xlsx")
else:
    wb.save(filename=f"testdir/sample.xlsx")

答案 14 :(得分:-1)

过了一会儿,但是仍然有类似的东西应该可以正常工作,这对某人很有用。

您可以使用内置的迭代器执行此操作(以图像下载器为例):

def image_downloader():

        image_url = 'some_image_url'

        for count in range(10):
            image_data = requests.get(image_url).content

            with open(f'image_{count}.jpg', 'wb') as handler:
                handler.write(image_data)

文件将正确增加。结果是:

image.jpg
image_0.jpg
image_1.jpg
image_2.jpg
image_3.jpg
image_4.jpg
image_5.jpg
image_6.jpg
image_7.jpg
image_8.jpg
image_9.jpg