什么决定了Path.GetTempPath()的返回值?

79

目前,我使用Path.GetTempPath()来确定日志文件的写入位置,但最近我遇到了一台用户机器,该路径返回的不是我所期望的。

通常,返回的路径是C:\Documents and Settings\[userid]\Local Settings\Temp,但在这种情况下,它是C:\Temp

这通常不是问题,但由于某些原因,该用户没有权限写入C:\Temp

我仔细检查了环境变量,发现USER环境变量指向预期的C:\Documents and Settings\[userid]\Local Settings\Temp,而SYSTEM环境变量则指向C:\WINNT\Temp

那么...Path.GetTempPath()从哪里获取它的值?组策略?注册表?

我已经谷歌搜索过了,但没有结果。


8
+1 快速、清晰、明了、好问题——欢迎来到StackOverflow。 - Nick Craver
如果您需要一个始终适用于用户的安全可写空间,请查看独立存储:http://msdn.microsoft.com/en-us/library/bdts8hk0.aspx - marc_s
1
@marc_s:除非启用了FIPS,否则在尝试使用IsolatedStorage时会出现异常。 - adrianbanks
@adrian:有趣——谢谢你的指点。这是我第一次听到这样的东西(可能是因为在欧洲,我们并不太关心“FIPS”之类的东西……)。 - marc_s
6个回答

70

(使用Reflector) Path.GetTempPath() 最终调用的是 Win32 函数 GetTempPath(来自kernel32.dll)。该函数的 MDSN 文档说明如下:

GetTempPath 函数按照以下顺序检查环境变量的存在性并使用第一个找到的路径:

  • TMP 环境变量指定的路径。
  • TEMP 环境变量指定的路径。
  • USERPROFILE 环境变量指定的路径。
  • Windows 目录。

请注意,他们也指出它不检查路径是否真实存在或可写入,因此您可能会尝试将日志文件写入不存在或无法访问的路径。


很棒的答案!清晰、简洁,正是我所需要的信息。我没有想到要查阅Win32函数文档……非常感谢。Andy - Andy Blackman
1
Path.GetTempPath() 的较新文档在“Remarks”下具有非常相似的内容。 - chwarr
这并不是这种情况,我只是回显了我的环境变量,在系统属性中检查它们并执行了Path.GetTempPath(),它们并不相同:http://imgbox.com/L1CDsEBe - Tod

17

免责声明:不是答案,但是需要认真阅读!

非常重要的一点是要意识到您需要清理临时文件,因为当您在单个目录中达到65536时,框架将不会再创建任何文件并且您的应用程序将崩溃!

这些文件会在数月内积累,然后您将收到以下消息:

System.IO.IOException: The file exists.

  at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
  at System.IO.__Error.WinIOError()
  at System.IO.Path.InternalGetTempFileName(Boolean checkHost)
  at System.IO.Path.GetTempFileName():

当您尝试构建时,TFS会向您提供这个:

TF215097: An error occurred while initializing a build for build 
definition XXXXX: The file exists. 

你所需要做的就是浏览到Path.GetTempPath()文件夹并调用del tmp*

注意:如果你有一个创建临时文件的ASP.NET应用程序,它的临时目录可能与当前登录用户不同。

如果不确定(或惊慌失措),只需创建一个aspx页面来打印出正在使用的位置:

 TempPath.aspx
 <%@ Page Language="C#"%>
 Temp path: <%= System.IO.Path.GetTempPath() %>

当我作为NetworkService运行时,我会得到以下结果。

 C:\Windows\TEMP\

当以AppPool(名为www.example.com)运行时,路径可能是:

 C:\Users\www.example.com\AppData\Local\Temp

顺便说一下,我认为即使你之后删除了该文件,这种情况仍然可能发生,因为文件名会增加。


11
今天早上到办公室发现生产系统崩溃了。原来我们的一位开发人员在其他地方使用 Path.GetTempFileName() 生成随机文件名,但他不知道这也会在 c:\windows\temp 中创建一个零字节的文件。看来系统尝试创建第 65537 个文件时就出问题了!幸好有人两年前发布了这条评论,否则可能要浪费数小时的时间。谢谢你! - cjuk
1
对于未来的检查:据我记得,Path.GetTempFileName()方法只返回类似“_00001.tmp”的内容,并且每次调用都会增加1。当它获得"_65537.tmp" - 文件的最大计数 - 下一次调用将尝试返回"_00001.tmp"(如果文件不存在)。如果存在,则会抛出错误。因此,最好保持干净的Temp文件名缓存{简单地说,当您不再需要它时,只需删除该文件}。希望这有所帮助。 - sihirbazzz
我喜欢保持在32000个文件以下,以确保安全;-) 我仍然没有弄清楚为什么立即删除我的tmp文件并没有真正删除它 - 并且没有备份或病毒保护运行,这可能会导致锁定文件。 - Simon_Weaver
感谢今天随机点赞的人。我检查了一下,我的文件数量又增加到了31480个! - Simon_Weaver

3
如果您正在使用Mono FrameworkMacOS上使用C#,那么Path.GetTempPath()返回的值是环境变量TMPDIR的值。
通常运行echo $TMPDIR会返回类似以下的值:
/var/folders/{2 character random-string}/{random-string}/T

2
我注意到 GetTempPath() 函数可以返回本地用户的 Documents & Settings\user\Local Settings\Temp 路径,如果是控制台应用程序,并且可以在从客户端运行的 Web 应用程序中返回 C:\WINDOWS\Temp (在服务器上)。前一种情况下,这不是什么大问题 - 运行应用程序的帐户有该文件夹的访问权限。在后一种情况下,如果应用程序池标识帐户(或您在 Web.config 文件中使用的模拟帐户)没有服务器上 C:\WINDOWS\Temp 的权限(这是很大的可能性),那么这可能是一个大问题。因此,对于我的控制台应用程序,为了确保临时文件写入的位置没有问题,将字符串硬编码到 INI 文件中是最好、最简单的方法;而对于 Web 应用程序,将其硬编码到 web.config 中并使用 ConfigurationManager.AppSettings ["myKey"] 来获取它的值,或者如果是 Web 应用程序,则使用此函数将文件发送到 ASP 临时文件夹并在那里处理它。
public static string findFileDirectory(string file)
{
    // Get the directory where our service is being run from
    string temppath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    // Ensure proper path notation so we can add the INI file name
    if (!temppath.EndsWith(@"\")) temppath += @"\";

    return temppath;
}

并且可以像这样调用:

    string tempFolderPath = findFileDirectory("Web.config");
    tempFolderPath = tempFolderPath.Replace(@"\\", @"\");

只需使用“tempFolderPath”替换之前使用的Path.GetTempPath()即可。这个函数非常好用,我在我的代码中使用它来代替那个邪恶的GetTempPath()方法,所以我知道我的应用程序可以完成它需要做的事情,因为ASP临时文件夹应该拥有其操作所需的所有权限(DOMAIN\NETWORK SERVICE和App Pool ID帐户需要完全控制)。tempFolderPath以斜杠结尾,因此只需直接与您的变量/文件名连接即可获得正确的路径。
-Tom
P.S. 您需要添加2个命名空间才能使该函数正常工作:System.IO和System.Reflection

2
请尝试使用以下方法确定数据的良好存储位置:
Environment.GetFolderPath(Environment.SpecialFolder folder);

特殊文件夹的位置在哪里?

// Summary:
//     Specifies enumerated constants used to retrieve directory paths to system
//     special folders.
[ComVisible(true)]
public enum SpecialFolder
{
  // Summary:
  //     The logical Desktop rather than the physical file system location.
  Desktop = 0,
  //
  // Summary:
  //     The directory that contains the user's program groups.
  Programs = 2,
  //
  // Summary:
  //     The directory that serves as a common repository for documents.
  Personal = 5,
  //
  // Summary:
  //     The "My Documents" folder.
  MyDocuments = 5,
  //
  // Summary:
  //     The directory that serves as a common repository for the user's favorite
  //     items.
  Favorites = 6,
  //
  // Summary:
  //     The directory that corresponds to the user's Startup program group.
  Startup = 7,
  //
  // Summary:
  //     The directory that contains the user's most recently used documents.
  Recent = 8,
  //
  // Summary:
  //     The directory that contains the Send To menu items.
  SendTo = 9,
  //
  // Summary:
  //     The directory that contains the Start menu items.
  StartMenu = 11,
  //
  // Summary:
  //     The "My Music" folder.
  MyMusic = 13,
  //
  // Summary:
  //     The directory used to physically store file objects on the desktop.
  DesktopDirectory = 16,
  //
  // Summary:
  //     The "My Computer" folder.
  MyComputer = 17,
  //
  // Summary:
  //     The directory that serves as a common repository for document templates.
  Templates = 21,
  //
  // Summary:
  //     The directory that serves as a common repository for application-specific
  //     data for the current roaming user.
  ApplicationData = 26,
  //
  // Summary:
  //     The directory that serves as a common repository for application-specific
  //     data that is used by the current, non-roaming user.
  LocalApplicationData = 28,
  //
  // Summary:
  //     The directory that serves as a common repository for temporary Internet files.
  InternetCache = 32,
  //
  // Summary:
  //     The directory that serves as a common repository for Internet cookies.
  Cookies = 33,
  //
  // Summary:
  //     The directory that serves as a common repository for Internet history items.
  History = 34,
  //
  // Summary:
  //     The directory that serves as a common repository for application-specific
  //     data that is used by all users.
  CommonApplicationData = 35,
  //
  // Summary:
  //     The System directory.
  System = 37,
  //
  // Summary:
  //     The program files directory.
  ProgramFiles = 38,
  //
  // Summary:
  //     The "My Pictures" folder.
  MyPictures = 39,
  //
  // Summary:
  //     The directory for components that are shared across applications.
  CommonProgramFiles = 43,
}

1
它调用GetTempPath函数。文档解释了它检查哪些环境变量。

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