创建文件但如果名称存在添加数字
Posted
技术标签:
【中文标题】创建文件但如果名称存在添加数字【英文标题】:Create file but if name exists add number 【发布时间】:2012-11-30 22:06:18 【问题描述】:如果文件名已经存在,Python 是否有任何内置功能可以将数字添加到文件名中?
我的想法是它会像某些操作系统的工作方式一样工作 - 如果一个文件被输出到一个已经存在同名文件的目录,它会附加一个数字或增加它。
即:如果“file.pdf”存在,它将创建“file2.pdf”,下一次创建“file3.pdf”。
【问题讨论】:
这通常是应用程序或程序创建文件的功能,所以不,没有像这样的本机功能。给定目录和文件名,您可以自己创建一些东西。 看看这个code.activestate.com/recipes/… 检查filename_fix_existing(filename)
【参考方案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
【讨论】:
【参考方案2】:在某种程度上,Python 将此功能内置于 tempfile
模块中。不幸的是,您必须使用私有全局变量tempfile._name_sequence
。这意味着正式地,tempfile
不保证在未来的版本中_name_sequence
甚至存在——它是一个实现细节。
但是,如果您无论如何都可以使用它,这将显示您如何在指定目录(例如 /tmp
)中创建格式为 file#.pdf
的唯一命名文件:
import tempfile
import itertools as IT
import os
def uniquify(path, sep = ''):
def name_sequence():
count = IT.count()
yield ''
while True:
yield 'sn: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'))
【讨论】:
感谢您的回答!从文档中找出棘手的东西;)我选择了我自己的,更简单的方法,但是这个答案清楚地回答了我想知道的问题 是的,如果您不需要tempfile
的特殊功能,这可能是一个明智的选择。 tempfile
模块努力避免某些竞争条件、安全性和拒绝服务攻击。使用顺序编号使上述代码容易受到拒绝服务攻击。而且我也不完全确定上述内容是否可以避免竞争条件或其他安全风险。【参考方案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
以防万一有人偶然发现并需要更简单的东西。
【讨论】:
非常好用,我用os.path.isfile(fname)
逻辑效果很好【参考方案4】:
如果所有文件都被编号没有问题,并且您事先知道要写入的文件的名称,您可以简单地这样做:
import os
counter = 0
filename = "file.pdf"
while os.path.isfile(filename.format(counter)):
counter += 1
filename = filename.format(counter)
【讨论】:
最优雅的!【参考方案5】:最近我遇到了同样的事情,这是我的方法:
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
【讨论】:
【参考方案6】:由于 tempfile hack A) 是一种 hack,而 B) 仍然需要大量代码,因此我采用了手动实现。你基本上需要:
-
Safely create a file if and only if it does not exist 的一种方式(这是 tempfile hack 为我们提供的)。
文件名生成器。
隐藏混乱的包装函数。
我定义了一个可以像 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)
【讨论】:
谢谢!你不需要做一些特别的事情来让它被用作上下文吗? 该函数只需要返回一个文件句柄——这就是内置的 open() 函数所做的一切。另请参阅***.com/questions/3774328/…【参考方案7】:假设我已经有了这些文件:
此函数生成下一个可用的非现有文件名,必要时在扩展名前添加 _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
【讨论】:
【参考方案8】:我还没有对此进行测试,但它应该可以工作,迭代可能的文件名,直到有问题的文件不存在,此时它会中断。
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
【讨论】:
【参考方案9】:这对我有用。
初始文件名为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
【讨论】:
【参考方案10】: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
【讨论】:
【参考方案11】:我发现 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 开始),但很容易改变它。
【讨论】:
【参考方案12】:我用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_nosuffix"
return str(path_file_name)
请注意:该解决方案从01
开始,并且只会找到包含-\d\d
的文件模式!
【讨论】:
【参考方案13】:稍晚一点,但仍然有这样的东西应该可以正常工作,mb它对某人有用。
您可以使用内置的迭代器来执行此操作(图像下载器作为您的示例):
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
【讨论】:
它似乎没有回答原始问题。问题是关于处理与预先存在的文件的冲突,而不是如何创建一些不相互冲突的文件名。【参考方案14】: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")
【讨论】:
以上是关于创建文件但如果名称存在添加数字的主要内容,如果未能解决你的问题,请参考以下文章