更改文件名称,直到它是唯一的

时间:2014-03-27 15:55:37

标签: python

我有一个脚本可以从预定的网页列表中下载文件(pdf,docs等)。如果文件名已经存在,我想编辑我的脚本以更改带有_x的文件的名称,因为来自不同页面的可能文件将共享相同的文件名但包含不同的内容,urlretrieve()似乎会自动覆盖现有文件。

到目前为止,我有:

urlfile = 'https://www.foo.com/foo/foo/foo.pdf'
filename = urlfile.split('/')[-1]
filename = foo.pdf
if os.path.exists(filename):
    filename = filename('.')[0] + '_' + 1

这适用于一次,但看起来在一个foo_1.pdf之后它将开始保存为foo_1_1.pdf,依此类推。我想将文件保存为foo_1.pdffoo_2.pdf等等。

有人能指出我正确的方向,我可以确保在脚本运行时以正确的方式存储文件名吗?

感谢。

4 个答案:

答案 0 :(得分:4)

所以你想要的是这样的:

    curName = "foo_0.pdf"

    while os.path.exists(curName):
        num = int(curName.split('.')[0].split('_')[1])
        curName = "foo_{}.pdf".format(str(num+1))

以下是一般方案:

  1. 假设您从第一个文件名(foo_0.pdf
  2. 开始
  3. 检查是否已采用该名称
  4. 如果是,请按1
  5. 重复名称
  6. 继续循环,直到找到未采用的名称
  7. 一种替代方法:生成正在使用的文件编号列表,并根据需要进行更新。如果它已排序,您可以说name = "foo_{}.pdf".format(flist[-1]+1)。这样做的好处是您不必每次都运行所有文件(如上面的解决方案所做的那样)。但是,您需要将数字列表保留在内存中。此外,这不会填补数字中的任何空白

答案 1 :(得分:1)

为什么不使用tempfile module

fileobj = tempfile.NamedTemporaryFile(suffix='.pdf', prefix='', delete = False)

现在您的文件名将在fileobj.name中提供,您可以操纵您心中的内容。作为额外的好处,这是跨平台的。

答案 2 :(得分:0)

import os
def uniquify(path, sep=''):
    path = os.path.normpath(path)
    num = 0
    newpath = path
    dirname, basename = os.path.split(path)
    filename, ext = os.path.splitext(basename)
    while os.path.exists(newpath):
        newpath = os.path.join(dirname, '{f}{s}{n:d}{e}'
                               .format(f=filename, s=sep, n=num, e=ext))
        num += 1
    return newpath

filename = uniquify('foo.pdf', sep='_')

可能出现的问题包括:

  1. 如果你用相同的方式打电话来统一数千次 路径,每次后续调用可能会慢一点 while-loop每次都会从num=0开始检查。
  2. uniquify容易受到竞争条件的影响,而文件可能不会 调用os.path.exists时存在,但可能存在于tempfile.NamedTemporaryFile 你使用uniquify返回的值的时间。使用 prefix以避免此问题。你不会得到的 增量编号,但您将获得具有唯一名称的文件, 保证不存在。您可以使用import tempfile import os def uniquify(path, sep='_', mode='w'): path = os.path.normpath(path) if os.path.exists(path): dirname, basename = os.path.split(path) filename, ext = os.path.splitext(basename) return tempfile.NamedTemporaryFile(prefix=filename+sep, suffix=ext, delete=False, dir=dirname, mode=mode) else: return open(path, mode) 参数 指定文件的原始名称。例如,

    In [141]: f = uniquify('/tmp/foo.pdf')       
    In [142]: f.name
    Out[142]: '/tmp/foo_34cvy1.pdf'
    

    可以这样使用:

    {{1}}

    请注意,为了防止竞争条件,将返回打开的文件句柄 - 而不仅仅是文件的名称。

答案 3 :(得分:0)

由于您正在处理多个页面,因此这看起来更像是“全局存档”而不是每页存档。对于每页存档,我会回答@wnnmaw的答案

对于全球档案,我会采取不同的方法......

  1. 为每个文件名创建一个目录
  2. 将文件作为“1”+扩展名
  3. 存储在目录中
  4. 将当前“数字”写为目录“_files.txt”
  5. 其他文件写为2,3,4等,并在_files.txt
  6. 中增加值

    这样做的好处:

    • 目录是原始文件名。如果你继续将“Example-1.pdf”变成“Example-2.pdf”,你可能会下载一个真正的“Example-2.pdf”,并且无法将它与原始文件名相关联。
    • 您可以通过阅读_files.txt或计算目录中的文件数来获取同名文件的数量。

    就个人而言,我还建议将文件存储在分层存储系统中,这样你就不会在任何一个目录中拥有太多的文件/目录(数百个文件会让用户感到讨厌,成千上万的文件可以影响操作系统性能)。存储系统可能会将文件名转换为hexdigest,然后将文件放入`/%s /%s /%s“%(hex [0:3],hex [3:6],filename)。使用hexdigest为你提供更均匀的角色分配。