检查fstream是文件还是目录

我使用C ++ fstream来读取配置文件。

#include <fstream>
std::ifstream my_file(my_filename);

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

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

我似乎无法找到办法:

  • 从给定的ifstream获取文件描述符。
  • 使用其他机制在ifstream中查找此信息。
  • 在某些论坛讨论中,有人认为这两者都不可能,因为这是依赖于操作系统的,因此永远不可能成为fstream C ++标准的一部分。

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

    #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);
    }
    

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


    void assertGoodFile(const char* fileName) {
       ifstream fileOrDir(fileName);
       //This will set the fail bit if fileName is a directory (or do nothing if it is already set  
       fileOrDir.seekg(0, ios::end);
       if( !fileOrDir.good()) {
          throw BadFile();
       };
    }
    

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

  • 忽略它。 说真的,如果目录内容作为有效配置通过,我会感到惊讶。 否则,解析将失败,因此您不会导入导致错误数据的风险。 此外,您不妨碍用户提供管道或类似非文件的东西。
  • 打开之前请检查路径。 你可以使用stat()或直接使用Boost.Filesystem或类似的库。 如果有任何类似的东西被添加到C ++ 11中,我不会100%确定。 请注意,这会产生竞争条件,因为在您检查之后但在打开之前,某些攻击者可能会用目录切换文件。
  • 通常,有办法从fstream检索低级句柄,在你的情况下可能是FILE* 。 还有一些方法可以从FILE*创建iostream (不一定是fstream !)。 这些都是特定于实现的扩展,因此您需要一些#ifdef魔术来定制特定于使用的stdlibrary实现的代码。 我敢于依赖他们的存在,即使不是你仍然可以在FILE*上创建一个streambuf ,如果你需要移植到一个不能提供更简单方法的模糊系统。

  • 由于IO操作的操作系统依赖性,认为是复杂的。

    我在OS X 10.10.2,Linux 2.6.32和FreeBSD 8.2-RELEASE上尝试了一些技巧(后两个稍微老一些,我使用了一些较老的VirtualBox虚拟机)。

  • 我还没有找到一种防呆方法。 如果你真的想检查,在路径上使用stat() ,或者在fstat()使用老式的C open() fstat()
  • seekg(0, std::ios::beg); PSkocik建议的方法不适用于我。
  • 对于fstreams,最好的方法就是打开并从文件中读取数据,并等待出错。
  • badbit和failbit都必须设置,特别是在OS X上,以便引发所有必需的异常。 例如my_file.exceptions(std::ios::failbit | std::ios::badbit);
  • 读取常规文件后,这也会导致文件结束(EOF)异常,这需要代码忽略这些正常的异常。
  • my_file.eof()也可能会设置更严重的错误,所以对EOF条件进行很差的检查。
  • errno是一个更好的指标:如果发生异常,但errno仍然为0,它很可能是EOF条件。
  • 这并非总是如此。 在FreeBSD 8.2上,打开目录路径只会返回二进制gobbledygook,而不会引发异常。
  • 这是在我测试过的3个平台上似乎处理它的实现。

    #include < iostream>
    #include < fstream>
    #include < cerrno>
    #include < cstring>
    
    int main(int argc, char *argv[]) {
       for (int i = 1; i < argc; i++) {
    
          std::ifstream my_file;
          try {
             // Ensure that my_file throws an exception if the fail or bad bit is set.
             my_file.exceptions(std::ios::failbit | std::ios::badbit);
             std::cout << "Read file '" << argv[i] << "'" << std::endl;
             my_file.open(argv[i]);
             my_file.seekg(0, std::ios::end);
          } catch (std::ios_base::failure& err) {
             std::cerr << "  Exception during open(): " << argv[i] << ": " << strerror(errno) << std::endl;
             continue;
          }
    
          try {
             errno = 0; // reset errno before I/O operation.
             std::string line;
             while (std::getline(my_file, line))
             {
                std::cout << "  read line" << std::endl;
                // ...
             }
          } catch (std::ios_base::failure& err) {
             if (errno == 0) {
                std::cerr << "  Exception during read(), but errono is 0. No real error." << std::endl;
                continue; // exception is likely raised due to EOF, no real error.
             }
             std::cerr << "  Exception during read(): " << argv[i] << ": " << strerror(errno) << std::endl;
          }
       }
    }
    
    链接地址: http://www.djcxy.com/p/84245.html

    上一篇: Check if a fstream is either a file or directory

    下一篇: Preferred way of patching multiple methods in Python unit test