【问题标题】:How to create a std::ofstream to a temp file?如何为临时文件创建 std::ofstream?
【发布时间】:2010-10-04 17:15:51
【问题描述】:

好的,mkstemp 是在 POSIX 中创建临时文件的首选方式。

但它会打开文件并返回一个int,这是一个文件描述符。由此我只能创建一个 FILE*,但不能创建一个 std::ofstream,我更喜欢在 C++ 中使用它。 (显然,在 AIX 和其他一些系统上,您可以从文件描述符创建 std::ofstream,但是当我尝试这样做时,我的编译器会报错。)

我知道我可以使用tmpnam 获得一个临时文件名,然后用它打开我自己的 ofstream,但由于竞争条件,这显然是不安全的,并导致编译器警告(Linux 上的 g++ v3.4.):

warning: the use of `tmpnam' is dangerous, better use `mkstemp'

那么,是否有任何可移植的方式来创建一个 std::ofstream 到一个临时文件?

【问题讨论】:

    标签: c++ file file-io mkstemp


    【解决方案1】:

    我已经完成了这个功能:

    #include <stdlib.h>
    #include <fstream>
    #include <iostream>
    #include <vector>
    
    std::string open_temp(std::string path, std::ofstream& f) {
        path += "/XXXXXX";
        std::vector<char> dst_path(path.begin(), path.end());
        dst_path.push_back('\0');
    
        int fd = mkstemp(&dst_path[0]);
        if(fd != -1) {
            path.assign(dst_path.begin(), dst_path.end() - 1);
            f.open(path.c_str(), 
                   std::ios_base::trunc | std::ios_base::out);
            close(fd);
        }
        return path;
    }
    
    int main() {
        std::ofstream logfile;
        open_temp("/tmp", logfile);
        if(logfile.is_open()) {
            logfile << "hello, dude" << std::endl;
        }
    }
    

    您可能应该确保使用正确的文件创建掩码调用 umask(我更喜欢 0600)- mkstemp 的联机帮助页说文件模式创建掩码不是标准化的。它使用 mkstemp 将其参数修改为它使用的文件名这一事实。因此,我们打开它并关闭它打开的文件(因此,不要打开它两次),留下一个连接到该文件的 ofstream。

    【讨论】:

    • 我想知道仅使用 std::string 作为模板并使用 (char *) dst.path.c_str() 是否安全。对于 std::string 的最明智的实现似乎没问题。
    • ididak,这不安全。指向的 c 字符串不可写 :)
    • 在 C++11 中,std::string 可以取消引用它的第一个条目。因此你可以通过 &somestring[0];到一个需要 char* 的函数。见:en.cppreference.com/w/cpp/string/basic_string
    • @X-Istence: 是的,但是在 GCC 中要小心 pre-5.1: stackoverflow.com/q/12199710/560648
    【解决方案2】:

    我认为这应该可行:

        char *tmpname = strdup("/tmp/tmpfileXXXXXX");
        ofstream f;
        int fd = mkstemp(tmpname);
        f.attach(fd);
    

    编辑:好吧,这可能不是便携式的。如果您不能使用附加并且不能直接从文件描述符创建 ofstream,那么您必须这样做:

    char *tmpname = strdup("/tmp/tmpfileXXXXXX");
    mkstemp(tmpname);
    ofstream f(tmpname);
    

    由于 mkstemp 已经为您创建了文件,因此这里的竞争条件应该不是问题。

    【讨论】:

    • 这不能在 Linux 上用我的 g++ v3.4.4 编译。显然只有部分平台有这个功能。
    • 谢谢!对于您的第二种方法(使用 mkstemp 然后使用 ofstream):在 I/O 方面仍然有效吗?那将访问文件系统两次,对吧?我们的文件系统超级慢,我担心它会给它带来不必要的负担。
    • mkstemp 可能失败并返回 -1;你的代码应该能捕捉到这种情况。
    • 另外第二个例子是泄露mkstemp返回的文件描述符。
    • 在使用strdup之后也需要调用free。
    【解决方案3】:

    也许这会起作用:

    char tmpname[256];
    ofstream f;
    sprintf (tmpname, "/tmp/tmpfileXXXXXX");
    int fd = mkstemp(tmpname);
    ofstream f(tmpname);
    

    我没试过,但你可以检查一下。

    【讨论】:

      【解决方案4】:
      char tempFileName[20]; // name only valid till next invocation of tempFileOpen
      ofstream tempFile;
      void tempFileOpen()
      {
          strcpy(tempFileName, "/tmp/XXXXXX");
          mkstemp(tempFileName);
          tempFile.open(tempFileName);
      }
      

      此代码也适用于 GCC/libstdc++6 4.8.4 和 Clang 3.9。也感谢其他对我有帮助的回复。

      【讨论】:

        猜你喜欢
        • 2017-03-06
        • 2017-08-10
        • 1970-01-01
        • 2011-04-24
        • 2019-05-17
        • 1970-01-01
        • 2010-09-17
        • 2011-05-19
        • 1970-01-01
        相关资源
        最近更新 更多