Как создать std:: ofstream для временного файла?

хорошо, mkstemp является предпочтительным способом создания временного файла в POSIX.

но он открывает файл и возвращает int, который является файловым дескриптором. Из этого я могу создать только файл*, но не std::ofstream, который я бы предпочел в C++. (По-видимому, в AIX и некоторых других системах вы можете создать std::ofstream из файлового дескриптора, но мой компилятор жалуется, когда я пытаюсь это сделать.)

Я знаю, что могу получить имя временного файла с tmpnam а затем открыть свой собственный ofstream с ним, но это, по-видимому, небезопасно из-за условий гонки и приводит к предупреждению компилятора (g++ v3.4. на Linux):

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

Итак, есть ли какой-либо портативный способ создать std::ofstream во временный файл?

4 ответов


Я думаю, что это должно работать:

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

EDIT: Ну, это не может быть портативным. Если вы не можете использовать attach и не можете создать ofstream непосредственно из файлового дескриптора, то вам нужно сделать следующее:

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

As mkstemp уже создает файл для вас, условия конкуренции не должно быть проблемой здесь.


Я сделал эту функцию:

#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('');

    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)- manpage для mkstemp говорит, что маска создания режима файла не стандартизирована. Он использует тот факт, что mkstemp изменяет свой аргумент на имя файла, которое он использует. Итак, мы открываем его и закрываем файл, который он открыл (так, чтобы он не открывался дважды), оставаясь с ofstream, который подключен к этому файлу.


возможно, это сработает:

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

Я не пробовал, но можно проверить.


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. Благодаря другим ответам, которые были полезны для меня.