【问题标题】:How to check if a string has a valid file path or directory path format in unmanaged C++ code?如何检查字符串在非托管 C++ 代码中是否具有有效的文件路径或目录路径格式?
【发布时间】:2015-02-19 16:23:03
【问题描述】:

我想知道如何检查(在非托管 Visual C++ 代码中)字符串是否具有表示文件路径或文件夹路径的有效格式。在这种情况下,物理文件或文件夹路径本身可能存在也可能不存在。检查正确的字符串格式是我的主要目标。我需要知道一个字符串是否具有作为有效文件路径的正确格式,或者它没有?有很多关于 C# 的帖子,但没有一篇关于非托管 C++ 的帖子。 Visual C++中的非托管C++怎么做?

【问题讨论】:

  • 在 c++ 中,您可以尝试使用regex 来执行此操作。
  • 任何字符串都是有效路径。什么是它应该拒绝的例子?
  • 例如:“C:\MainFolder\MyFolder\myTextFile.txt”或“MyFolder\myTextFile.txt”是相应的绝对路径和相对路径。但是“C:^^>\:_Wrong_path”是错误的路径示例。
  • stackoverflow.com/questions/1976007/… 请注意,您无法检查 100% 的可靠性,文件系统可以施加自己的限制。
  • 只是“尝试使用它”(例如,打开文件名进行读取,或者如果您打算创建,打开以进行写入)。

标签: c++ filepath string-formatting


【解决方案1】:

唯一 100% 确定的方法是“尝试”。您可以编写代码来确定简单的情况,但总会有一些问题需要处理,除非您还找出文件所在的驱动器是哪个文件系统,因为 Windows 允许“连接”,这意味着解析整个路径一直到最后一部分。

做起来要简单得多:

  std::ifstream test(proposedName); 
  if (!test)
  {
      std::cout << "The file doesn't exist" << std::endl;
  }

如果你真的想花哨,你可以看看errno,看看它是“无效文件名”还是“文件不存在”。但总的来说,尝试再次猜测文件名和路径的有效性是没有意义的,因为有太多的规则可能适用于您的特定情况,也可能不适用。

如果您有“中途”不存在的目录,情况会变得更加复杂。您只需要解析路径并尝试在途中创建目录[如果整个过程失败则再次删除它]。但是,由于您必须处理非规范路径,这使情况变得更加复杂。 c:\blah\..\.\foo\..\bar\xxx.9\..\..\bleurgh\papa.txt 是有效的文件名吗?要解决这个问题,您必须首先规范化名称。

PathCanonicalize 或者它的朋友会帮助解决这个问题。但它仍然充满了非常难以解决的令人讨厌的复杂问题。

当然,您可以尝试编写正则表达式或其他东西来捕捉简单的情况,但最终还是会遇到难以弄清楚的情况。

请注意,在某些情况下,路径可能看起来有效,但实际上并非如此。假设我们有这条路径:c:\directory\foo\bar.txt。现在,这看起来完全有效,我们可能必须在其中创建 c:\direoctryfoo。但是如果c:\directory\foo 是一个已经存在的文件呢?您会删除该文件并在其位置创建一个目录吗?或者您会说它“很好”,然后在您尝试创建目录时失败?我不知道答案,而这种复杂性就是为什么我说“唯一确定的方法就是尝试它”——其他一切都只是在追你的尾巴,或者逼近正确性。

当然,如果我们将文件权限考虑在内,情况会变得更加复杂。

[而且 erenon 提出了一个很好的观点——即使你现在检查它,在你检查某些东西和你真正开始使用你的路径之间,你很可能已经对目录结构进行了更改,从而使以前有效的名称无效 -反之亦然——这类问题通常被称为“TOCTOU”——“检查时间到使用时间”]

【讨论】:

  • 为什么需要规范化文件名以检查它是否以正确的格式编译?
  • 因为不正确的“上一个目录”可能是“无效”,例如'c:\..\foo.txt' 无效,但不包含任何无效组合...
  • 实际上PathCanonicalize 至少在某种程度上也会验证名称,如果名称无效则返回FALSE。我不相信这足以确保“永远好名声”,但这是一个开始。
  • 我认为 'C:\..\foo.txt' 就格式而言是有效的,即使它在文件存在方面可能无效。我将问题读作“我有一个字符串和路径语法,但没有要检查的文件系统;这个字符串是否有正确的语法”。
  • 对,这取决于您要达到的目标。是的,您所说的很可能是正确的,并且支票应该接受这条路径。但它在当前存在的每个 Windows 文件系统上仍然无效。
【解决方案2】:

如果您合并了最新版本的 boost,您可以使用 FileSystem 为您完成这项工作并解决所有常见问题(\ vs \\ 等...)。 它还提供了一些其他功能(文件大小、权限等...)

#include <boost/filesystem.hpp>

string filePath= "C:\Temp\myExample.txt";
if (boost::filesystem::exists(filePath))    // does filePath actually exist?
    cout<<"This is a valid file";
else
    cout<<"The file does not exist";

这是链接。

http://www.boost.org/doc/libs/1_47_0/libs/filesystem/v3/doc/tutorial.html

它应该在某个时候在官方 C++ 中,完整的细节在这里。

http://en.cppreference.com/w/cpp/experimental/fs

希望对你有帮助,

【讨论】:

  • exists 用词不当。不,代码不检查文件是否存在。它检查文件是否可访问,或至少可查询。假设代码调用者的安全令牌不授予对 C:\Temp 的访问权限。此时您的检查失败,即使 myExample.txt 很可能在那里。
【解决方案3】:

我认为 Mats Petersson 的回答描述了真正的答案。我想指出一个常见的错误。假设如下函数:

bool fileExists(const char* fileName)
{
  std::ifstream test(fileName); 
  return (test) ? true : false;
}

然后这样使用它:

if (fileExists(myFile))
{
  // assume myFile is a valid file
  // WRONG!
}

这里有一个巨大的竞争条件。 myFile 在检查后但在使用前可能会失效。确保它确实存在的唯一方法是打开它并保留文件句柄。

【讨论】:

    猜你喜欢
    • 2011-03-09
    • 2014-12-05
    • 1970-01-01
    • 2012-09-08
    • 2022-12-15
    • 2019-03-28
    • 2011-09-06
    • 2014-05-05
    • 2018-06-21
    相关资源
    最近更新 更多