Подтвердить что ты не робот

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Ответ 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/libstdС++ 6 4.8.4 и Clang 3.9. Благодаря другим ответам, которые были полезны для меня.