代码之家  ›  专栏  ›  技术社区  ›  asdoylejr

更改文件名,直到其唯一

  •  0
  • asdoylejr  · 技术社区  · 10 年前

    我有一个脚本,可以从预定的网页列表中下载文件(pdf、文档等)。我想编辑我的脚本以更改文件名 _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.pdf , foo_2.pdf 等等

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

    谢谢

    4 回复  |  直到 10 年前
        1
  •  4
  •   wnnmaw    10 年前

    所以你想要的是这样的:

        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. 如果是,则将名称重复1
    4. 继续循环,直到找到未使用的名称

    一种选择: 生成正在使用的文件编号列表,并根据需要进行更新。如果排序好,你可以说 name = "foo_{}.pdf".format(flist[-1]+1) 。这有一个优点,即您不必每次都运行所有文件(正如上面的解决方案所做的那样)。但是,您需要将数字列表保存在内存中。此外,这不会填补数字中的任何空白

        2
  •  1
  •   hd1 Madan Sapkota    10 年前

    为什么不直接使用 tempfile module :

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

    现在,您的文件名将在fileobj.name中可用,您可以尽情操作。作为一个额外的好处,这是跨平台的。

        3
  •  0
  •   Jonathan Vanasco    10 年前

    因为您要处理多个页面,所以这看起来更像是一个“全局归档”,而不是每页归档。对于每页存档,我会使用@wnnmaw的答案

    对于全球存档,我会采取不同的方法。。。

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

    这样做的好处:

    • 目录是原始文件名。如果你一直将“Example-1.pdf”转换为“Example-2.pdf”,你可能会下载一个真正的“Example-2.pdf”,并且无法将其与原始文件名相关联。
    • 您可以通过读取files.txt或计算目录中的文件数来获取类似命名文件的数量。

    就我个人而言,我还建议将文件存储在分层存储系统中,这样在任何一个目录中都不会有太多的文件/目录(数百个文件会让用户感到烦恼,数千个文件会影响操作系统的性能)。打包系统可能会将文件名转换为十六进制摘要,然后将文件放入“/%s/%s/%s”%(hex[0:3],hex[3:6],filename)。十六进制摘要用于使字符分布更均匀。

        4
  •  0
  •   unutbu    10 年前
    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 被调用,但可能存在于 使用uniquify返回的值的时间。使用 tempfile.NamedTemporaryFile 以避免这个问题。你不会得到 递增编号,但您将获得具有唯一名称的文件, 保证不存在。你可以使用 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'
      

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