所以我正在开发一个应用程序,它需要创建一个文件,写入它,调用另一个程序,该文件是一个输入,并删除该文件。
我寻找可能的解决方案,一个解决方案看起来像这样。
std::FILE* tmpf = std::tmpfile();
std::fputs("Hello, world", tmpf);
根据std::tmpfile
的文档,如果文件是手动关闭,或者程序以自然方式退出,则文件将被删除。这看起来很好,但有一个例外。它看起来很乱(使用C I / O,而不是C ++流)。
另一种解决方案是使用std::tmpnam
,它将生成唯一的文件名。
std::string file_name = std::tmpname(NULL);
// (*)
std::fstream stream{file_name};
stream << "Hello World" << std::endl;
但是这个也存在问题。如果另一个程序创建了具有相同名称的文件,而我的程序在(*)
,我们将在同一个文件上进行操作,这当然是我想避免的。
C ++ STL(仍然)不支持文件系统操作,例如检查文件是否存在。我可以使用stat
之类的东西来检查它,但是因为检查文件并创建它不是原子的,所以它不能解决任何问题。而且我没有找到原子操作的C ++ STL方法,它会:检查文件是否存在,如果没有,打开它,如果是,则失败。
所以,我的问题是,解决这个问题的正确方法是什么?我错过了什么吗?
答案 0 :(得分:2)
这是我几乎没有凌乱的解决方案:
#include <cstdio>
#include <iostream>
#include <string>
#include <ext/stdio_filebuf.h> // libstdc++ specific
int main()
{
__gnu_cxx::stdio_filebuf<char> tmpfile_buf{std::tmpfile(), std::ios::in | std::ios::out | std::ios::binary};
std::iostream tmpstream{&tmpfile_buf};
// write in stream
tmpstream << "Hello World" << std::endl;
tmpstream.seekg(0);
// read from stream
std::string str;
std::getline(tmpstream, str);
std::cout << str << std::endl;
}
使用 std::tmpfile()
,并从具有底层FILE*
的缓冲区构建流。这是一个GNU扩展,因此不可移植:(。
答案 1 :(得分:2)
您的规范“...创建一个文件,写入其中,使用该文件调用另一个程序是一个输入,然后删除该文件。”与tmpfile()不兼容。首先,没有(便携式)方法从tmpfile()获取FILE指针获取文件名,其次在POSIX平台上,tmpfile()通常会在从tmpfile()返回之前从目录中删除文件(如果你不熟悉POSIX文件系统语义,只要你的进程有一个打开的文件描述符,即使它从目录中删除后,该文件仍然存在,这意味着无法从文件系统访问它。)
鉴于此,您将不得不使用某种tmpname()类型方法,并找出一种方法来防止两个进程同时访问它(文件锁定,使用stat()检查链接计数等)。
或者更好的是,不要使用文件进行进程间通信。对于最简单的(?)情况,在父节点中创建一个管道,将它连接到子节点的标准输入。
答案 2 :(得分:0)
我可能会提出Boost解决方案,但我无法在此进行测试。
从FILE*
返回std::tmpfile()
,可以获得文件描述符:
#include <cstdio>
FILE* const tmpfile = std::tmpfile();
const int fd = ::fileno(tmpfile);
在这个阶段,使用boost::iostreams::file_descriptor_source
:
#include <boost/iostreams/code_converter.hpp>
#include <boost/iostreams/maped_file.hpp>
file_descriptor_source tmpstream(fd, boost::iostreams::close_handle);