如何在Unix和Windows中获取系统或用户临时文件夹?

34

我正在编写一个C++问题。它需要在Windows和Unix操作系统上工作。

如何在不同的操作系统中获取用户或系统的临时文件夹?


不要再写更多问题了,我们已经有足够的问题了。这一次写一个解决方案吧。 :-) 你需要实际的临时文件夹,还是只需要一个临时文件?C++没有文件系统的概念,因此不存在“文件夹”,但你可以使用tmpfile或者tmpnam来获取一个临时文件。 - Kerrek SB
еңЁWindowsдёҠпјҢзӣёеә”зҡ„еҮҪж•°жҳҜGetTempFileNameгҖӮ - Matteo Italia
1
tmpfile函数不会给你一个文件名;tmpnam函数会给你一个文件名,但是并不安全(请参阅mkstemp(),它可以同时给你文件名和文件描述符,并且是安全的)。 - Jonathan Leffler
@KerrekSB 现在 C++ 有 https://en.cppreference.com/w/cpp/filesystem - AsukaMinato
8个回答

53

更新:感谢 @RoiDanton,最新的答案是 std::filesystem::temp_directory_path(C++17)


尝试使用boost::filesystemtemp_directory_path(),它内部使用:

  • ISO/IEC 9945 (POSIX):由列表TMPDIRTMPTEMPTEMPDIR中找到的第一个环境变量所指定的路径。如果没有找到这些变量,则使用"/tmp",或者如果定义了宏__ANDROID__,则使用"/data/local/tmp"

  • Windows:由Windows GetTempPath API函数报告的路径。

有趣的是,Windows 的 GetTempPath 使用与 POSIX 版本类似的逻辑:列表中的第一个环境变量是 TMPTEMPUSERPROFILE。如果没有找到这些变量,则返回 Windows 目录。

这些方法主要依赖于环境变量似乎有点不太好。但这就是它们的决定方式。既然它真的很平凡,你可以很容易地使用 cstdlibgetenv 函数自己编写代码,特别是如果你想要特定顺序的优先级或不想使用其他库。


2
这是最好的跨平台答案,应该被接受。 - Luis
3
此外,C++14/C++17已成为C++标准的一部分:http://en.cppreference.com/w/cpp/filesystem/temp_directory_path - Roi Danton

10

按照POSIX标准,使用$TMPDIR环境变量。

char const *folder = getenv("TMPDIR");
if (folder == 0)
    folder = "/tmp";

1
使用环境变量有很多需要注意的地方。它们可能在某些提升权限的情况下不可用,或者可能被对手(或疏忽)恶意更改。 - Kerrek SB
是的,存在安全问题 - 但我不知道是否有更广泛可用的标准替代方案。您可以(可能应该)在临时目录中创建一个安全子目录(特别是如果值为“/ tmp”),以保存文件。请注意,POSIX要求如果路径名名称为符号链接,“mkdir(2)”应失败并将errno设置为[EEXIST]。Linux表示当“路径名已经存在(不一定是作为目录)”时,“mkdir(2)”会生成EEXIST。这包括路径名是符号链接(悬挂或不悬挂)的情况。因此,创建目录是安全的。 - Jonathan Leffler
TMP 适用于 Windows,不是 TMPDIR - T.Todua

4
如果你在使用QT(Core),你可以尝试使用QString QDir::tempPath(),或者在代码中使用它的实现(因为QT是开源的,所以可以查看他们是如何实现的)。
文档中说:在Unix/Linux系统上,通常是/tmp;在Windows系统中,通常是TEMP或TMP环境变量中指定的路径。

0
根据文档,最大路径为MAX_PATH(260)。 如果路径恰好为260,则上面示例中的代码(也就是plougy)将失败,因为将返回261。 可能缓冲区大小应该为MAX_PATH + 1。
TCHAR szPath[MAX_PATH + 1];
DWORD result = GetTempPath(MAX_PATH + 1, szPath);
if (result != ERROR_SUCCESS) {
    // check GetLastError()
}   

-1

便捷函数:

std::string getEnvVar( std::string const & key )
{
    char * val = getenv( key.c_str() );
    return val == NULL ? std::string("") : std::string(val);
}

我猜TEMP或其他什么参数可以被传递?当然,这取决于操作系统。getenv是stdlib的一部分,因此应该也是可移植的。


-1
如果您可以访问main()函数的代码,最好的方法可能是通过main()的**argv将必要的文件夹名称传递,并使用与操作系统相关的批处理启动器。例如,在UNIX中:
bash a_launcher.sh

其中 a_launcher.sh 就像这样

./a.out /tmp

-1
在Windows上:使用GetTempPath()来检索指定为临时文件的目录的路径。
wstring TempPath;
wchar_t wcharPath[MAX_PATH];
if (GetTempPathW(MAX_PATH, wcharPath))
  TempPath = wcharPath;

-1

这些例子都不是非常具体,并没有提供一个工作示例(除了 std::filesystem::temp_directory_path),而是指向了微软的文档,下面是一个使用“GetTempPath()”的工作示例(在 Windows 10 上测试通过):

//temp.cpp
#include <iostream>
#include <windows.h>


int main()
{ 
    TCHAR path_buf[MAX_PATH];
    DWORD ret_val = GetTempPath(MAX_PATH, path_buf);
    if ( ret_val > MAX_PATH || (ret_val == 0) )
    {
        std::cout << "GetTempPath failed";
    } else {
        std::cout << path_buf;
    }
}

输出:

C:\>temp.exe
C:\Users\username\AppData\Local\Temp\

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