【问题标题】:How to generate name of non-existent file and block its creation?如何生成不存在文件的名称并阻止其创建?
【发布时间】:2013-12-04 09:07:05
【问题描述】:

我想在我的程序中测试“没有这样的文件”行为。为此(当然)我需要一些文件名,它将指向不存在的文件。

有什么方法可以生成这样的文件名并保证它在测试完成之前不存在? - 我没有任何想法,所以我实际上什么都没尝试。

我想用 C++ 实现它,但实际上,这不是 C++ 特定的问题。


更新 #1

至少为 Linux 找到解决方案是可以接受的。

【问题讨论】:

  • 经典 XY 问题。你真正想要完成什么?
  • @EJP 我正在尝试检查,如果所需的文件不存在,我的程序会生成某些错误。
  • 删除它,然后运行有问题的方法。
  • 如果您只是想测试一个文件是否不存在,并且从不实际创建该文件,那么为什么不硬编码到您的系统永远不会自动创建的路径和文件呢?那么并行运行多少进程并不重要。
  • 您的应用程序或测试框架是否在该应用程序/测试框架独有的特定路径中运行?然后只需在该路径中搜索no_such_file_should_ever_exist_here。是的,有人可能会手动创建该文件,但可能不是您的应用程序/测试框架,除非被告知要特别这样做(您永远不会这样做)。

标签: c++ linux unix


【解决方案1】:

可能无法获得 100% 的保证,但您可以 通过以下方式轻松防止其他用户创建的任何内容 首先创建一个只有你有访问权限的目录, 然后在那里创建文件。之后,由您决定 确保你不做任何你不想要的事情。 (作为一般 规则,任何时候你需要临时文件,创建一个目录 属于你的,只有你可以访问的,是一个好的 预防措施。)

【讨论】:

  • 这是一个很好的建议,但总有一个“root”,它可能会更改权限、删除我宝贵的文件夹或只是在那里创建文件......但我认为这比依赖概率更好文件名生成器。
  • @abyss.7 root 的角色要求它能够与您的假设相矛盾。它还可以无缘无故地终止您的进程,甚至(至少在 Unix 下)导致它看起来有段违规。原则上,您无能为力来阻止 root 与您相处。 (Windows 的保护机制比 Unix 的保护机制稍微复杂一些,但最终,必须有一个管理员可以做任何事情,因为它是必要的,以便能够修复其他用户可能搞砸的事情。 )
  • @abyss.7 关于文件名生成器的概率:通常 如果 您使用名称来创建目录而不是文件就足够了。 (如果您只使用 Unix,您可能对 mkdtemp 感兴趣,它会创建一个具有唯一名称的新目录。)
【解决方案2】:

在 Windows 上使用 _tempnam,在 POSIX(例如 Linux 或 OSX)上使用 tempnam

【讨论】:

  • 从您的链接中引用:“在创建路径名和打开文件之间,其他进程可以创建具有相同名称的文件。”
  • @abyss.7 是的,这就是为什么它被标记为过时的,以支持创建实际文件的函数。但是,如果您使用一个特殊的目录,而您知道没有(或很少)程序会将切片添加到(即,不是系统临时目录),那么您不太可能遇到这个问题。
  • 这是一种概率解决方案,当测试在构建农场上运行时(临时文件和文件夹经常被创建),这在某些情况下几乎是不可接受的。直到我确定所有程序都使用相同的文件名生成器并且我知道它的内部结构——确保它的统计属性——我不能使用它们中的任何一个。
  • @abyss.7 在这种情况下,您必须自己制作。也许使用 UUID? (参见例如here for linux
  • 传统上,tmpnamstandard 函数)将进程 ID 改造成名称。如果是这样,使用它来创建目录应该不会导致问题(但如果情况变得更糟,您可以循环直到它工作)。或者,如果需要,编写自己的、修改 PID 甚至一些随机文本也不是很困难。
【解决方案3】:

实际上不可能创建一个不存在的文件名(竞争条件)。您可以使用 stdio 函数 'char *tmpnam(char *s);' 获取名称这会生成一个难以猜测的名称。

你可以组成一个流来避免名字被猜到的不太可能的情况:

class NoFStream : public std::fstream
{
    public:
    NoFStream(const char*, ios_base::openmode = ios_base::in | ios_base::out) {
        setstate(ios_base::failbit);
    }

    void open(const char*, ios_base::openmode = ios_base::in | ios_base::out) {
        setstate(ios_base::failbit);
    }
};

int main()
{
    NoFStream f("/tmp/file");
    if(f >> std::ws) std::cout << "This will not succeed" << std::endl;
    else std::cout << "Ok - it fails" << std::endl;
    return 0;
}

【讨论】:

    猜你喜欢
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多