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

目前,我使用 Path.GetTempPath()来确定在哪里写日志文件,但最近我遇到了一个用户的机器,返回的路径与我预期的不一样。

通常,返回的路径是 < strong > C: Document and Settings [ userid ] Local Settings Temp 但在本例中,它是 < strong > C: Temp

这通常不会是一个问题,但由于某些原因,该用户无法写入 C: 临时工

我反复检查了环境变量,当系统环境变量指向 C: WINNT 临时工时,USER 环境变量指向 C: 文档和设置[ userid ]本地设置临时值

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

我谷歌过了,但是没有结果。

37950 次浏览

It calls the GetTempPath function. The documentation explains what environment variables it checks.

(Using Reflector) Path.GetTempPath() ultimately calls the Win32 function GetTempPath (from kernel32.dll). The MDSN docs for this state:

The GetTempPath function checks for the existence of environment variables in the following order and uses the first path found:

  • The path specified by the TMP environment variable.
  • The path specified by the TEMP environment variable.
  • The path specified by the USERPROFILE environment variable.
  • The Windows directory.

Note that they also state that it doesn't check whether or not the path actually exists or can be written to, so you may end up trying to write your log files to a path that doesn't exist, or one that you cannot access.

I've noticed GetTempPath() can bring back the local user's Documents & Settings\user\Local Settings\Temp path if it's a console application, and noticed it can bring back C:\WINDOWS\Temp (on the server) if it's a web app being ran from a client. In the former case, no big deal - the account running the app has the rights to that folder. In the latter, maybe it is a big deal if the App Pool Identity account (or account you may be using to impersonate with in the Web.config file for the web app) doesn't have privileges to C:\WINDOWS\Temp on the server (which is a big chance it doesn't). So for my console apps, just so there's no question where temp files are written, hard-coding a string into an INI file is the best and easiest for me, and for a web app, hard-coding it in the web.config and getting it using ConfigurationManager.AppSettings["myKey"] works, or if it's a web app, use this function to send the file to the ASP Temporary Files folders and work with it there:

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;
}

and call it like this:

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

and just use "tempFolderPath" instead of where you used Path.GetTempPath() before. This function works awesome & I use it in my code in place of this evil GetTempPath() method so I know my app can do what it needs to do, since the ASP Temp Files folder should have all the permissions it needs for its operations (DOMAIN\NETWORK SERVICE and App Pool ID account need Full Control). tempFolderPath ends in a trailing slash, so just concat directly with your variable/file name to get the right path going.

-Tom

P.S. You need to add 2 namespaces to make that function work: System.IO and System.Reflection

Please try using the following to determine good place for Your data:

Environment.GetFolderPath(Environment.SpecialFolder folder);

Where Specialfolder

// 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,
}

Disclaimer: Not an answer - but important reading !

It's very important to realize that you need to clear up your temp files becuase when you hit 65536 in a single directory the framework won't create any more and your app will blow up!

They will accumulate over months and months and then you'll get a message like this:

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():

and TFS will give you this when you try to build:

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

All you need to do is do is browse to the Path.GetTempPath() folder and call del tmp*

Note: If you have an ASP.NET appliation creating temp files its temp directory will probably be different than the current logged in user

If in doubt (or in panic) just create an aspx page to print out the location being used:

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

For me when running as NetworkService I get

 C:\Windows\TEMP\

When running as an AppPool (named www.example.com) the path may be:

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

PS. I think this can happen even if you delete the file afterwards becasue the filename increases.

If you are using C# on MacOS using Mono Framework then value returned by Path.GetTempPath() is value of environment variable TMPDIR.

Running echo $TMPDIR usually returns value like :

/var/folders/{2 character random-string}/{random-string}/T