检查fstream是文件还是目录

Mac*_*eek 9 c++ fstream ifstream c++11 fstat

我正在使用C++ fstream来读取配置文件.

#include <fstream>
std::ifstream my_file(my_filename);
Run Code Online (Sandbox Code Playgroud)

现在,如果我传递一个目录的路径,它会默默地忽略它.my_file.good()即使my_filename是目录,Eg 也会返回true .由于这是我的程序的意外输入,我喜欢检查它,并抛出异常.

如何检查刚打开的fstream是否是常规文件,目录或流?

我似乎无法找到一种方法:

  • 从给定的ifstream获取文件描述符.
  • 使用其他一些机制在ifstream中查找此信息.

一些论坛讨论中,有人认为这两者都不可能,因为这是依赖于操作系统的,因此永远不会成为fstream C++标准的一部分.

我能想到的唯一选择是重写我的代码以完全摆脱ifstream并使用文件描述符(*fp)的C方法,以及fstat():

#include <stdio.h>
#include <sys/stat.h>
FILE *fp = fopen(my_filename.c_str(), "r");
// skip code to check if fp is not NULL, and if fstat() returns != -1
struct stat fileInfo;
fstat(fileno(fp), &fileInfo);
if (!S_ISREG(fileInfo.st_mode)) {
    fclose(fp);
    throw std::invalid_argument(std::string("Not a regular file ") + my_filename);
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢fstream.因此,我的问题.

Ulr*_*rdt 2

有不同的方法来解决这个问题:

  1. 忽略它。说真的,如果目录内容作为有效配置通过,我会感到惊讶。如果没有,解析无论如何都会失败,因此您不会面临导入错误数据的风险。此外,您不会阻止用户提供管道或类似的非文件内容。
  2. 打开之前检查路径。您可以使用stat()或直接使用 Boost.Filesystem 或一些类似的库。我不能 100% 确定 C++11 中是否添加了类似的内容。请注意,这会产生竞争条件,因为在检查之后但在打开之前,某些攻击者可能会使用目录切换文件。
  3. 通常,有多种方法可以从 检索低级句柄fstream,在您的情况下可能是FILE*. 还有一些方法可以从 a创建一个iostream(不一定是一个!) 。这些始终是特定于实现的扩展,因此您需要一些魔法来定制特定于所使用的 stdlibrary 实现的代码。我敢于依赖它们的存在,即使没有,如果您需要移植到一些不提供更简单方法的晦涩系统,您仍然可以创建一个on tof 。fstreamFILE*#ifdefstreambufFILE*