web-dev-qa-db-ja.com

一時ファイルにstd :: ofstreamを作成する方法は?

さて、POSIXで一時ファイルを作成するにはmkstempが推奨される方法です。

ただし、ファイルを開き、ファイル記述子であるintを返します。それから、私はFILE *のみを作成できますが、C++で好むstd::ofstreamは作成できません。 (どうやら、AIXや他のいくつかのシステムでは、ファイル記述子からstd::ofstreamを作成できますが、それを試みるとコンパイラーが文句を言います。)

tmpnamで一時ファイル名を取得し、それを使用して独自のストリームを開くことができることはわかっていますが、競合状態のために明らかに安全ではなく、コンパイラの警告が発生します(Linuxではg ++ v3.4)。

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

それで、一時ファイルにstd::ofstreamを作成する移植可能な方法はありますか?

36
Frank

私はこれがうまくいくと思います:

    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はすでにファイルを作成しているので、ここでは競合状態は問題になりません。

11
f3lix

私はこの機能を実行しました:

#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が引数を使用するファイル名に変更するという事実を使用します。そのため、ファイルを開いて閉じ、開いたファイルを閉じます(つまり、2回開かないようにするため)。そのファイルに接続されているofstreamが残ります。

多分これはうまくいくでしょう:

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

試したことはありませんが、確認できます。

2
nerdy
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 ++ 64.8.4およびClang3.9でも機能します。私に役立った他の返信にも感謝します。

0
jamadagni