I am busy writing an application that runs under windows
Where is the correct place to save temporary files ?
If you are using .NET, please use Path.GetTempPath(). This will guarantee that you use the temporary directory assigned to the user that runs your application, regardless of where it is stored.
If you browse the file system, you will notice that there are many "temp" directories:
~\Temp
~\Windows\Temp
~\Users\userName\AppData\Local\Temp
... and many more. Some of these paths are OS-dependent, and won't be present on certain windows flavors. So, save yourself some time and hassle, and let the .NET framework figure out where the "temp" path is located.
Use GetTempPath and and possibly GetTempFileName to determine where to put your temporary files. This is the most reliable, enduser-friendly, and future proof way to get a temporary location for files.
In the temp directory?
Use GetTempPath or in a batch file %TEMP%
C:\Temp is NOT a good choice.
If you are using .Net use code like this:
string baseFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string cfgFolder = Path.Combine(baseFolder, "MyAppName");
try
{
if (!Directory.Exists(cfgFolder))
{
Directory.CreateDirectory(cfgFolder);
}
}
catch { } // If no access, not much we can do.
to get a place for medium-term storage of app data, or Path.GetTempPath() for transient storage of data.
Use the GetTempPath API, or the equivalent for your programming environment.
It depends on the language you are using:
string tempFolder = System.IO.Path.GetTempPath();
will return you the appropriate folder in C# for instance.
or, the environment variables TEMP or TMP if you must.
C:\Documents and Settings\username\Application Data\IsolatedStorage
Related
Is it possible to get the path of system folders in Go, in a cross-platform way? eg. temp folders, "document" folders, etc.
I found ioutil.TempFolder/File but they do something different. Any idea?
There's currently no way to access standard system folders in a cross-platform way. The Home directory though can be access using the user package:
u, _ := user.Current()
fmt.Println(u.HomeDir)
In the year 2020, I am trying to get similar things, but only for temporary directory cross-platform. When I found this thread and read some answers, I almost make a conclusion that it is not possible.
But after a few further research, I found that go already have it. Just like pointed by the accepted answer, it stands inside os package. Based on this documentation: https://golang.org/pkg/os/#TempDir, we can get it by calling: TempDir() function.
If someone trying to look at another OS system directories path, and stumbled upon in this thread, my suggestion, please just try to have a few further research. Looks like currently go have more complete functions regarding OS system directories.
A built-in option doesn't exist yet. Your best bet is to open an issue and submit a feature request.
In the meantime you can add support yourself by using platform specific +build flags. With that you have a couple of options:
Use the os package to get the information for each system, possibly through the shell.
Use cgo with existing C / C++ methods. See this answer, which explains how to get this information using C++ for Windows.
It may also be helpful to read the source code of the os package to see how platform-specific information is obtained. This could help you devise a way to get this information, and perhaps submit a patch to be included.
For the OS's temp directory, as stated by Bayu, there is a built-in function os.TempDir() string to get the os specific temp directory:
// TempDir returns the default directory to use for temporary files.
//
// On Unix systems, it returns $TMPDIR if non-empty, else /tmp.
// On Windows, it uses GetTempPath, returning the first non-empty
// value from %TMP%, %TEMP%, %USERPROFILE%, or the Windows directory.
// On Plan 9, it returns /tmp.
//
// The directory is neither guaranteed to exist nor have accessible
// permissions.
func TempDir() string {
return tempDir()
}
which is actually used by the ioutil.TempDir(dir, pattern string) (string, error) function if you provide an empty string for the dir parameter. Check out the 5th and 6th lines:
// TempDir creates a new temporary directory in the directory dir.
// The directory name is generated by taking pattern and applying a
// random string to the end. If pattern includes a "*", the random string
// replaces the last "*". TempDir returns the name of the new directory.
// If dir is the empty string, TempDir uses the
// default directory for temporary files (see os.TempDir).
// Multiple programs calling TempDir simultaneously
// will not choose the same directory. It is the caller's responsibility
// to remove the directory when no longer needed.
func TempDir(dir, pattern string) (name string, err error) {
Besides the methods Luke mentioned, on Windows you can get some of the paths from environment variables. Same applies, to some extent, to Unix ($HOME, etc.).
I need to get a safe temp folder where I could store temporary files for my application, but so far my research has lead me to conclusion that all approaches I've found are flawed.
The first idea was to use GetTempPath function, but that causes two problems:
The folder might not exist, so I would have to truncate folders one by one up to root, and recreate them if they do not exist back to full path (error prone, tedious)
From "Larry Osterman's WebLog" click it seems that GetTempPath might fallback to USERPROFILE or Windows directory and extract whole lot of files right in there, which is SUPER BAD(TM)!
In the same post, there is a suggestion to use GetEnvironmentVariable, but this seems a dangerous function to me (missing TMP & TEMP envvars for instance).
Is there a cleaner function I could use? Seems that SHGetKnownFolderPath has no clue what temp folder is.
Your program is probably not the only one to rely on GetTempPath, so it's reasonable to expect it to return a proper writable path. Especially since Windows automatically initializes the TMP and TEMP environment variables for you; someone would have to go to some trouble to override them, and it would be their responsibility to make sure the change did not mess up their system.
I would go ahead and assume GetTempPath works properly, and worry about failures when you try to create the temporary file - there are other errors that might occur at that time that you need to check for anyway.
An idea would be to get the path where your application is (GetModuleFileNameEx combined with GetModuleHandle(NULL) and GetCurrentProcess) since this directory cannot be deleted under windows as long as your application is running from it (maybe I'm wrong ...some years ago I couldn't do this :) ) and in this directory create a temporary directory.
Your first bullet point is the solution. Wrap it up in a method so that you don't duplicate code.
According to this answer, Boost's Filesystem library can be used for this.
When a process is running at the low integrity level, you can't write to %temp% so I need a way to find the path to the %temp%\Low directory (Without hardcoding the word "Low")
The "Finding Low Integrity Write Locations" section of the "Understanding and Working in Protected Mode Internet Explorer" article includes the following tidbit:
Note Protected Mode modifies IE's environment variables. As a result, the GetTempPath() function returns %Temp%\Low when called while Protected Mode is active.
According to MSDN
When in Protected Mode, extensions can
write files to a folder below the
user's UserProfile folder, typically
%userprofile%\AppData\LocalLow. Use
the SHGetKnownFolderPath function with
the FOLDERID_LocalAppDataLow flag to
obtain the expanded folder name.
SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0,
NULL, szPath, ARRAYSIZE(szPath));
If you're just looking for a temporary directory to write to, you could loop through the directories inside the %temp% directory and try to write to each.
If UAC is disabled, . should be the first. If not, .\Low should be the only one.
According to MSDN
"Low-integrity processes can write and create subfolders under %USER PROFILE%\AppData\LocalLow"
I don't think there's any way to avoid hardcoding thost last two folders.
If I have a string that resolves to a file path in Windows, is there an accepted way to get a canonical form of the file name?
For example, I'd like to know whether
C:\stuff\things\etc\misc\whatever.txt
and
C:\stuff\things\etc\misc\other\..\whatever.txt
actually point to the same file or not, and store the canonical form of the path in my application.
Note that simple string comparisons won't work, nor will any RegEx magic. Remember that we have things like NTFS reparse points to deal with since Windows 2000 and the new Libraries structure in Windows 7.
Short answer: not really.
There is no simple way to get the canonical name of a file on Windows. Local files can be available via reparse points, via SUBST. Do you want to deal with NTFS junctions? Windows shortcuts? What about \\?\-escaped filenames
Remote files can be available via mapped drive letter or via UNC. Is that the UNC to the origin server? Are you using DFS? Is the server using reparse points, etc.? Is the server available by more than one name? What about the IP address? Does it have more than one IP address?
So, if you're looking for something like the inode number on Windows, it ain't there. See, for example, this page.
Roger is correct, there is no simple way. If the volume supports file a unique file index, you can open the file and call GetFileInformationByHandle, but this will not work on all volumes.
The Windows API call GetFullPathName may be the best simple approach.
GetFinalPathNameByHandle appears to do what your asking for, which is available starting with Windows Vista.
Using FileInfo (example in C#):
FileInfo info1 = new FileInfo(#"C:\stuff\things\etc\misc\whatever.txt");
FileInfo info2 = new FileInfo(#"C:\stuff\things\etc\misc\other\..\whatever.txt");
if (info1.FullName.Equals(info2.FullName)) {
Console.WriteLine("yep, they're equal");
}
Console.WriteLine(info1.FullName);
Console.WriteLine(info2.FullName);
Output is:
yep, they're equal
C:\stuff\things\etc\misc\whatever.txt
C:\stuff\things\etc\misc\whatever.txt
jheddings has a nice answer, but since you didn't indicate which language you are using, I thought I'd give a Python way to do it that also works from the command line, using os.path.abspath:
> python -c "import os.path; print os.path.abspath('C:\stuff\things\etc\misc\other\..\whatever.txt')"
C:\stuff\things\etc\misc\whatever.txt
I would use System.IO.Path.GetFullPath. It takes a string as an input (C:\stuff\things\etc\misc\other..\whatever.txt in your case) and will output a string (C:\stuff\things\etc\misc\whatever.txt).
I guess I'm a little late, but you can use System.IO.Path.GetFullPath("C:\stuff\things\etc\misc\other..\whatever.txt") and it will return "C:\stuff\things\etc\misc\whatever.txt"
To get canonical path you should use PathCanonicalize function.
I have an asp.net app and I am trying to save a text file to a folder that changes with each client. How can I write it to save the files to a folder that changes. For example one customer might be C:\inetpub\wwwroot\site1\ another might be C:\inetpub\wwwroot\site2.
Relative paths don't seem to work, and I've tried GetCurrentDirectory but it kept giving me the wrong directory.
Thanks
You should try :
In the *.aspx.cs file :
string currentPath = Server.MapPath("~");
I don't have the tools to test here, but I think the code is right.
Take a look at Path.GetDirectoryName(Request.ServerVariables("SCRIPT_NAME")).
You should add a value to the web.config file which is set to the path where the file is saved.
Then, in you code, retrieve this value from the documentation, and use that path when saving.