Как создать std :: ofstream для временного файла? - PullRequest
35 голосов
/ 01 февраля 2009

Хорошо, 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 ]

16 голосов
/ 01 февраля 2009

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

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

11 голосов
/ 01 февраля 2009

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

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

РЕДАКТИРОВАТЬ: Ну, это может быть не переносимым. Если вы не можете использовать attach и не можете создать ofstream непосредственно из файлового дескриптора, тогда вам нужно сделать это:

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

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

2 голосов
/ 18 августа 2011

Может быть, это будет работать:

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

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

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

...