C++: 获得临时文件,跨平台

50
我正在寻找一种跨平台的方式来获取指定的临时文件。例如在Linux中,它会在/tmp目录中,在Windows中则类似于C:\Users\Username\AppData\Local\Temp
是否存在这样一个跨平台(使用Boost?)的解决方案?
编辑:我需要这个文件在程序终止之前存在。但tmpfile()无法保证这一点。引用ccpreference的话来说:
创建的临时文件在流被关闭(fclose)或者程序正常终止时自动删除。

1
你能否评论一下使用 tmpnam 无法满足你的需求? - jwd
@jwd:不好意思,我忘记接受一个答案了,这并不影响。 - orlp
7个回答

91

Boost Filesystem库从其3.0版本开始可以用于创建临时文件名。它还提供了简洁的解决方案。实际上,以下C++代码应该是跨平台的:

// Boost.Filesystem VERSION 3 required
#include <string>
#include <boost/filesystem.hpp>
boost::filesystem::path temp = boost::filesystem::unique_path();
const std::string tempstr    = temp.native();  // optional

文件系统路径对象temp可用于打开文件或创建子目录,而字符串对象tempstr以字符串的形式提供相同的信息。

2
这应该被接受 - tmpnam 可以成为攻击向量。 - Matt Clarkson
36
unique_path 只返回文件名。使用 boost::filesystem::temp_directory_path() / boost::filesystem::unique_path() 获取完整的临时文件路径名。 - JE42
7
对于那些想知道的人:unique_path() 函数由于可能引发竞争条件,不会成为 std::filesystem 的一部分。更多信息请参见 https://wg21.cmeerw.net/lwg/msg7747。 - Roi Danton
5
这个问题与 tmpnam() 完全相同。 - Timmmm
有人知道Windows 10的存储感应器删除临时文件是否安全吗? - Adrian B.

8

7
标准C库中包含一个名为tmpfile的函数,它可能是您需要的:http://www.cplusplus.com/reference/clibrary/cstdio/tmpfile/ 您也可以在C++程序中使用它。
编辑: 如果您只需要文件名,可以使用tmpnam,它在调用fclose时不会删除文件。它返回完整的文件路径,包括临时目录。
C方式:
const char *name = tmpnam(NULL);  // Get temp name
FILE *fp = fopen(name, "w");  // Create the file
// ...
fclose(fp);
remove(name);

和James所说的一样:这对我来说不是解决方案。我需要确保文件存在直到程序退出。引用ccpreference的话:“当流关闭(fclose)时,创建的临时文件会自动删除。” - orlp
7
使用tmpnam也会引入竞态条件。 - Frerich Raabe
tmpnam在符合C++14标准的系统上也无法工作,例如MSYS2下的GCC 5.4。我不知道"\s778."是什么临时名称,除了对于Windows系统来说完全不正确。那将是一个目录路径,而不是文件路径。 - Alex Huszagh
1
tmpnam在Android上不存在。 - mark.kedzierski
2
对于那些想知道tmpname引入了什么竞争条件的人,请参阅此链接:http://www.zachburlingame.com/2011/06/creating-temporary-files-on-win32-in-c-part-1/。 - smac89

4

4
这并不会创建一个临时文件,它只是提供了一个临时文件夹的名称。如果你把一个文件放在那里,它将会保留下来。 - user997112

3
您可以使用C标准库函数tmpfile

1
这对我来说不是解决方案。我需要在程序退出之前保证文件的存在。引用ccpreference的话:“当流关闭(fclose)时,创建的临时文件会自动删除。” - orlp
1
@nightcracker:好的...所以在使用临时文件完成之前不要关闭文件流? - James McNellis
1
这样做不会阻止外部程序访问吗(这正是我需要一个临时文件供其他程序读取的原因)?我在考虑使用 tmpnam - orlp
1
@nightcracker:外部程序如何知道要读取的文件名?你是以某种方式将其发送给它们吗?这感觉像是与临时文件的概念相矛盾。 - davka

2

编辑:特别是因为您似乎喜欢Boost的想法,Robbie Morrison的答案对您来说可能更好。

我的原始回答保留在下面,但是任何阅读此内容的人:请注意tmpnam是不安全的。此外,某些平台(如Windows)可能有损坏的、有缺陷的、愚蠢的甚至是缺失的实现。


如果您不喜欢tmpfile,那么tmpnam怎么样?

从链接中可以看到:

用这种方式创建的文件,与使用tmpfile创建的文件不同,在关闭时不会自动删除;在关闭后应调用remove来删除此文件。

特别是如果您需要另一个程序知道文件的名称,那么这似乎更合适,因为tmpfile根本不给您一个名称。

虽然我认为它不太安全,如果这是一个问题的话。这里有一个描述其中一些问题的链接


另外,即使您想使用tmpfile,您也应该考虑更安全的tmpfile_s(即使我怀疑它不会在未来十年内从C++标准中删除,但MS文档甚至称tmpfile为“已弃用”)。无论如何,这两者都不保留所需的命名文件。


2
来自Linux上的GCC:警告:使用tmpnam'是危险的,最好使用mkstemp'--但我猜测`mkstemp'不是跨平台的。 - André Puel
@André:mkstemptmpfile在原问题的限制方面存在相同的问题-它只会返回一个文件句柄。但你是对的,正如所指出的那样,tmpnam是不安全的。 - jwd
从Debian文档中:BUGS 不要使用这个函数,应该使用mkstemp(3)或tmpfile(3)。 - malat

-7

在程序之间进行通信的方式有很多比随机临时文件更好的选择。你可以考虑使用管道进行通信,或者使用本地主机套接字。

如果你坚持要使用文件,那么只需让你的程序使用一个名称,可能是基于启动时间的。


5
楼主询问如何以跨平台的方式创建临时文件,而不是询问这是否是一个好主意。这并没有帮助到他。 - jwm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接