【问题标题】:A way to create files and directories without overwriting一种无需覆盖即可创建文件和目录的方法
【发布时间】:2018-11-09 19:41:43
【问题描述】:

你知道当你下载一些东西并且下载文件夹包含一个同名的文件时,而不是覆盖它或抛出错误,文件最终会在末尾附加一个数字吗?比如我要下载my_file.txt,但是目标文件夹中已经存在,那么新的文件将命名为my_file(2).txt。如果我再试一次,它会是my_file(3).txt

我想知道 Python 3.x 中是否有办法检查它并获得一个唯一的名称(不一定要创建文件或目录)。我目前正在这样做:

import os
def new_name(name, newseparator='_')
    #name can be either a file or directory name

    base, extension = os.path.splitext(name)
    i = 2
    while os.path.exists(name):
        name = base + newseparator + str(i) + extension
        i += 1

    return name

在上面的示例中,如果 cwd 中已经存在 my_file.txt,则运行 new_file('my_file.txt') 将返回 my_file_2.txtname 也可以包含完整或相对路径,它也可以。

【问题讨论】:

  • 我不明白:你的问题是python函数覆盖文件/目录而不告诉你问题?或者如果文件已经存在,您是否想要一个自动将数字添加到文件名的内置函数?你永远找不到后者,因为它是特定于应用程序的,与操作系统无关。
  • pathlib 对于这样的事情真的很有帮助:docs.python.org/3/library/pathlib.html 特别是,请查看Path.touch(mode=0o666, exist_ok=True)
  • 所以...您编写了一个解决方案来解决您的问题,但您想知道它是否已经在某个地方得到解决并且是标准 Python 3 发行版的一部分?你介意解释一下原因吗?老实说,我真的不明白这一点
  • @Karl:这比更常见的“请什么内置函数完成以下复杂任务:(需求列表)”要好得多。
  • 是的,这是真的。我不知道我的语气是否带有讽刺意味。不是这个意思,我只是好奇。如果 OP 提出了一个好的解决方案,为什么不保留它呢?

标签: python python-3.x


【解决方案1】:

我会使用PathLib 并按照以下方式做一些事情:

from pathlib import Path 

def new_fn(fn, sep='_'):
    p=Path(fn)
    if p.exists():
        if not p.is_file(): 
            raise TypeError
        np=p.resolve(strict=True)
        parent=str(np.parent)
        extens=''.join(np.suffixes)  # handle multiple ext such as .tar.gz
        base=str(np.name).replace(extens,'')
        i=2
        nf=parent+base+sep+str(i)+extens    
        while Path(nf).exists():
            i+=1
            nf=parent+base+sep+str(i)+extens    
        return nf   
    else:       
        return p.parent.resolve(strict=True) / p 

这仅处理写入的文件,但同样的方法适用于目录(您稍后添加)。我将把它作为一个项目留给读者。

【讨论】:

  • 只为最后一行点赞!我只是不得不阅读文档以确认您没有犯愚蠢的错误;) 那么,斜杠运算符是否超载?
  • @usr2564301:是的,/os.path.join 等效。参见PEP 428p.parent.resolve(strict=True) / p 的作用是返回一个绝对路径,不管是用绝对路径、本地路径还是相对路径调用。
  • 教授一些我不知道的 PathLib 优势的奖励积分(如 Path.suffixesPath.resolve 之类的 sutff)。我会尝试从 os 转移到 PathLib。另外:我认为没有严格的内置方法可以做到这一点,所以我会接受他的回答。
【解决方案2】:

另一种获得新名称的方法是使用内置的tempfile 模块:

from pathlib import Path
from tempfile import NamedTemporaryFile

def new_path(path: Path, new_separator='_'):
    prefix = str(path.stem) + new_separator
    dir = path.parent
    suffix = ''.join(path.suffixes)

    with NamedTemporaryFile(prefix=prefix, suffix=suffix, delete=False, dir=dir) as f:
        return f.name

如果你在下载目录中执行这个函数,你会得到类似的东西:

>>> new_path(Path('my_file.txt'))
'/home/krassowski/Downloads/my_file_90_lv301.txt'

90_lv301 部分是由 Python 的 tempfile 模块在内部生成的。

注意:使用delete=False 参数,该函数将创建(并且不删除)具有新名称的空文件。如果您不想以这种方式创建空文件,只需删除 delete=False,但保留它会阻止其他人在您下一次操作之前创建具有该名称的新文件(尽管他们仍然可以覆盖它)。

简单地说,如果您(或最终用户)要同时运行您的程序两次,使用delete=False 可以防止并发问题。

【讨论】:

  • 我不熟悉符号“def fun(var : Class)”,用标点符号在谷歌上搜索很麻烦。这是否会运行某种断言来检查传递的值是否是该类的实例?
  • 不,如果给定的类型与预期的类型不匹配,它不会引发任何异常,只是为了让程序员提示他预期的类型(并且让 IDE 显示更好的建议)。它被称为type hint(ing),是在 Python 3.5 中引入的
  • 非常好。我很好奇为什么我没有经常看到它。
猜你喜欢
  • 1970-01-01
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-15
  • 2021-12-05
相关资源
最近更新 更多