336

I need to generate a unique temporary file with a .csv extension.

What I do right now is

string filepath = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");

However, this doesn't guarantee that my .csv file will be unique.

I know the chances I ever got a collision are very low (especially if you consider that I don't delete the .tmp files), but this code doesn't looks good to me.

Of course I could manually generate random file names until I eventually find a unique one (which shouldn't be a problem), but I'm curious to know if others have found a nice way to deal with this problem.

sergiol
4,3655 gold badges52 silver badges92 bronze badges
asked Feb 24, 2009 at 12:26
3
  • 6
    some caveats about GetTempFileName The GetTempFileName method will raise an IOException if it is used to create more than 65535 files without deleting previous temporary files. The GetTempFileName method will raise an IOException if no unique temporary file name is available. To resolve this error, delete all unneeded temporary files. Commented Nov 9, 2012 at 7:28
  • 2
    Temporary files are mainly uses for a specific set of conditions. If the file extension is important, I wonder if maybe using the GetTempFileName isn't the write solution. I know it's been a long time, but if you told us more about the context and need for these files, we might be able to suggest a better approach altogether. more here: support.microsoft.com/kb/92635?wa=wsignin1.0 Commented Nov 9, 2012 at 7:33
  • 2
    Keep in mind GetTempFileName() creates a new file each time you call it. -- If you immediately change the string to something else, you just created a new zero byte file in your temp directory (and as others have noted, this will eventually cause it to fail when you hit 65535 files in there...) -- To avoid this, make sure to delete any files that you create in that folder (including the ones returned by GetTempFileName(), ideally in a finally block). Commented Oct 23, 2018 at 23:53

18 Answers 18

432

Guaranteed to be (statistically) unique:

string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv"; 

(To quote from the wiki article on the probabilty of a collision:

...one's annual risk of being hit by a meteorite is estimated to be one chance in 17 billion [19], that means the probability is about 0.00000000006 (6 ×ばつ 10−11), equivalent to the odds of creating a few tens of trillions of UUIDs in a year and having one duplicate. In other words, only after generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%. The probability of one duplicate would be about 50% if every person on earth owns 600 million UUIDs

EDIT: Please also see JaredPar's comments.

answered Feb 24, 2009 at 12:29
Sign up to request clarification or add additional context in comments.

20 Comments

But not guaranteed to be in a writable location
And they are not guaranteed to be unique at all, just statistically unlikely.
@Pax: you have more chnace of winning the lottery 1000 times in a row than generating two idebtical guids. That's unique enough I guess...
@Mitch the reason it's not unique is because it's possible for me to simply create a file with the same name in the same path. GUIDs while guaranteed to be unique are also predictable which means given enough information I could guess the next set of guids generated by your box
good lord people, try harder to keep your head out of the clouds. The approach is: generate a random file name, then create it if it doesn't exist. So just help him code that nicely. All this talk about pseudo-random generators and universally unique numbers is totally unnecessary.
|
74

Try this function ...

public static string GetTempFilePathWithExtension(string extension) {
 var path = Path.GetTempPath();
 var fileName = Path.ChangeExtension(Guid.NewGuid().ToString(), extension);
 return Path.Combine(path, fileName);
}

It will return a full path with the extension of your choice.

Note, it's not guaranteed to produce a unique file name since someone else could have technically already created that file. However the chances of someone guessing the next guid produced by your app and creating it is very very low. It's pretty safe to assume this will be unique.

answered Feb 24, 2009 at 12:38

4 Comments

Perhaps Path.ChangeExtension() would be more elegant than Guid.NewGuid().ToString() + extension
@ohadsc - indeed, Guid.NewGuid().ToString() + extension is not even correct, it should be Guid.NewGuid().ToString() + "." + extension
I suppose that depends on the contract of the method (whether it expects .txt or txt) but since ChangeExtension handles both cases, it can't hurt
Call it Suffix instead of Extension and everyone is happy I guess
60
public static string GetTempFileName(string extension)
{
 int attempt = 0;
 while (true)
 {
 string fileName = Path.GetRandomFileName();
 fileName = Path.ChangeExtension(fileName, extension);
 fileName = Path.Combine(Path.GetTempPath(), fileName);
 try
 {
 using (new FileStream(fileName, FileMode.CreateNew)) { }
 return fileName;
 }
 catch (IOException ex)
 {
 if (++attempt == 10)
 throw new IOException("No unique temporary file name is available.", ex);
 }
 }
}

Note: this works like Path.GetTempFileName. An empty file is created to reserve the file name. It makes 10 attempts, in case of collisions generated by Path.GetRandomFileName();

answered Apr 14, 2012 at 9:20

2 Comments

Keep in mind that Path.GetRandomFileName() actually creates a zero-byte file on disk and returns the full path of that file. You are not using this file, only its name to change the extension. So, if you don't make sure that you are deleting these temporary files, after 65535 calls to this function it will begin to fail.
You have mixed GetTempFileName() and GetRandomFileName(). GetTempFileName() create a zero-byte file like my method, but GetRandomFileName() does not create a file. From the docs : > Unlike GetTempFileName, GetRandomFileName does not create a file. Your link points to the wrong page.
19

You can also alternatively use System.CodeDom.Compiler.TempFileCollection.

string tempDirectory = @"c:\\temp";
TempFileCollection coll = new TempFileCollection(tempDirectory, true);
string filename = coll.AddExtension("txt", true);
File.WriteAllText(Path.Combine(tempDirectory,filename),"Hello World");

Here I used a txt extension but you can specify whatever you want. I also set the keep flag to true so that the temp file is kept around after use. Unfortunately, TempFileCollection creates one random file per extension. If you need more temp files, you can create multiple instances of TempFileCollection.

answered Jul 14, 2009 at 2:03

Comments

11

The MSDN documentation for C++'s GetTempFileName discusses your concern and answers it:

GetTempFileName is not able to guarantee that the file name is unique.

Only the lower 16 bits of the uUnique parameter are used. This limits GetTempFileName to a maximum of 65,535 unique file names if the lpPathName and lpPrefixString parameters remain the same.

Due to the algorithm used to generate file names, GetTempFileName can perform poorly when creating a large number of files with the same prefix. In such cases, it is recommended that you construct unique file names based on GUIDs.

jnm2
8,4155 gold badges67 silver badges100 bronze badges
answered Oct 1, 2012 at 15:18

2 Comments

The GetTempFileName method will raise an IOException if it is used to create more than 65535 files without deleting previous temporary files. The GetTempFileName method will raise an IOException if no unique temporary file name is available. To resolve this error, delete all unneeded temporary files.
That is an incomplete quote. The relevant quote: "If uUnique is not zero, you must create the file yourself. Only a file name is created, because GetTempFileName is not able to guarantee that the file name is unique." If you call it the way everyone is discussing here, uUnique will be zero.
10

Why not checking if the file exists?

string fileName;
do
{
 fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
} while (System.IO.File.Exists(fileName));
answered Feb 24, 2009 at 13:25

5 Comments

File.Exists tells you information about the past and is hence not reliable. In between the return of File.Exist and your code executing it's possible for the file to be created.
... then you're safe with your own program maybe but not with other process writing a file on that exact same destination...
@JaredPar and what is propability of this happening?
@Migol It's very low, and by definition an exceptional condition. Hmmm, exactly what exceptions were designed to be used for.
@CodyGray chance for guid clash is 1/2^128. Chance that it would happen 2 times is 1/2^256 etc. Dont bother!
7

You can also do the following

string filepath = Path.ChangeExtension(Path.GetTempFileName(), ".csv");

and this also works as expected

string filepath = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
sergiol
4,3655 gold badges52 silver badges92 bronze badges
answered Feb 24, 2009 at 14:39

5 Comments

this will fail if there is a file temp.csv and you create temp.tmp and then change the extension to csv
No it won't...GetTempFileName() creates a unique filename...upto some limit of 32K at which point you need to delete some files but I think my solution is correct. It's wrong if I were to pass a file path into ChangeExtension that isn't guaranteed to be unique, but that's not what my solution does.
GetTempFileName guarantees that the path it returns will be unique. Not that the path it returns + ".csv" will be unique. Changing the extension in this way could fail as David said.
GetTempFileName creates a file, so your first example is a resource leak.
The first solution should have a warning, as it may eventually cause IOException "The file exists" when there are too many files in the %TEMP% directory.. The problem is that GetTempFileName() creates a physical empty file and returns its name. ChangeExtension() changes the string name, but not the name of the physical file, so the orginal .tmp file gets forgotten / leaks..
6

How about:

Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".csv")

It is highly improbable that the computer will generate the same Guid at the same instant of time. The only weakness i see here is the performance impact DateTime.Now.Ticks will add.

answered Jul 27, 2010 at 8:12

Comments

3

In my opinion, most answers proposed here as sub-optimal. The one coming closest is the original one proposed initially by Brann.

A Temp Filename must be

  • Unique
  • Conflict-free (not already exist)
  • Atomic (Creation of Name & File in the same operation)
  • Hard to guess

Because of these requirements, it is not a godd idea to program such a beast on your own. Smart People writing IO Libraries worry about things like locking (if needed) etc. Therefore, I see no need to rewrite System.IO.Path.GetTempFileName().

This, even if it looks clumsy, should do the job:

//Note that this already *creates* the file
string filename1 = System.IO.Path.GetTempFileName()
// Rename and move
filename = filename.Replace(".tmp", ".csv");
File.Move(filename1 , filename);
answered Jan 6, 2015 at 8:19

2 Comments

But that's not conflict free, the 'csv' could already exist and be overwritten.
File.Move raises IOException if the destination file already exists. msdn.microsoft.com/en-us/library/…
3

I mixed @Maxence and @Mitch Wheat answers keeping in mind I want the semantic of GetTempFileName method (the fileName is the name of a new file created) adding the extension preferred.

string GetNewTempFile(string extension)
{
 if (!extension.StartWith(".")) extension="." + extension;
 string fileName;
 bool bCollisions = false;
 do {
 fileName = Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString() + extension);
 try
 {
 using (new FileStream(fileName, FileMode.CreateNew)) { }
 bCollisions = false;
 }
 catch (IOException)
 {
 bCollisions = true;
 }
 }
 while (bCollisions);
 return fileName;
}
answered Oct 29, 2019 at 14:04

Comments

2

This could be handy for you... It's to create a temp. folder and return it as a string in VB.NET.

Easily convertible to C#:

Public Function GetTempDirectory() As String
 Dim mpath As String
 Do
 mpath = System.IO.Path.Combine(System.IO.Path.GetTempPath, System.IO.Path.GetRandomFileName)
 Loop While System.IO.Directory.Exists(mpath) Or System.IO.File.Exists(mpath)
 System.IO.Directory.CreateDirectory(mpath)
 Return mpath
End Function
answered May 30, 2011 at 12:49

Comments

1

This seems to work fine for me: it checks for file existance and creates the file to be sure it's a writable location. Should work fine, you can change it to return directly the FileStream (which is normally what you need for a temp file):

private string GetTempFile(string fileExtension)
{
 string temp = System.IO.Path.GetTempPath();
 string res = string.Empty;
 while (true) {
 res = string.Format("{0}.{1}", Guid.NewGuid().ToString(), fileExtension);
 res = System.IO.Path.Combine(temp, res);
 if (!System.IO.File.Exists(res)) {
 try {
 System.IO.FileStream s = System.IO.File.Create(res);
 s.Close();
 break;
 }
 catch (Exception) {
 }
 }
 }
 return res;
} // GetTempFile
answered Jul 25, 2011 at 12:52

Comments

1

This is a simple but effective way to generate incremental filenames. It will look in the current directly (you can easily point that somewhere else) and search for files with the base YourApplicationName*.txt (again you can easily change that). It will start at 0000 so that the first file name will be YourApplicationName0000.txt. if for some reason there are file names with junk between (meaning not numbers) the left and right parts, those files will be ignored by virtue of the tryparse call.

 public static string CreateNewOutPutFile()
 {
 const string RemoveLeft = "YourApplicationName";
 const string RemoveRight = ".txt";
 const string searchString = RemoveLeft + "*" + RemoveRight;
 const string numberSpecifier = "0000";
 int maxTempNdx = -1;
 string fileName;
 string [] Files = Directory.GetFiles(Directory.GetCurrentDirectory(), searchString);
 foreach( string file in Files)
 {
 fileName = Path.GetFileName(file);
 string stripped = fileName.Remove(fileName.Length - RemoveRight.Length, RemoveRight.Length).Remove(0, RemoveLeft.Length);
 if( int.TryParse(stripped,out int current) )
 {
 if (current > maxTempNdx)
 maxTempNdx = current;
 }
 }
 maxTempNdx++;
 fileName = RemoveLeft + maxTempNdx.ToString(numberSpecifier) + RemoveRight;
 File.CreateText(fileName); // optional
 return fileName;
 }
answered May 16, 2018 at 20:45

Comments

1

Based on answers I found from the internet, I come to my code as following:

public static string GetTemporaryFileName()
{ 
 string tempFilePath = Path.Combine(Path.GetTempPath(), "SnapshotTemp");
 Directory.Delete(tempFilePath, true);
 Directory.CreateDirectory(tempFilePath);
 return Path.Combine(tempFilePath, DateTime.Now.ToString("MMddHHmm") + "-" + Guid.NewGuid().ToString() + ".png");
}

And as C# Cookbook by Jay Hilyard, Stephen Teilhet pointed in Using a Temporary File in Your Application:

  • you should use a temporary file whenever you need to store information temporarily for later retrieval.

  • The one thing you must remember is to delete this temporary file before the application that created it is terminated.

  • If it is not deleted, it will remain in the user’s temporary directory until the user manually deletes it.

roschach
9,61617 gold badges92 silver badges141 bronze badges
answered Mar 1, 2019 at 8:04

Comments

0

This is what I am doing:

string tStamp = String.Format("{0:yyyyMMdd.HHmmss}", DateTime.Now);
string ProcID = Process.GetCurrentProcess().Id.ToString();
string tmpFolder = System.IO.Path.GetTempPath();
string outFile = tmpFolder + ProcID + "_" + tStamp + ".txt";
answered Apr 15, 2011 at 20:13

1 Comment

Good: includes process identifier Bad: does not include thread identifier (though you could run this inside a lock) Bad: timestamp is only 1 second resolution. In many, many applications, it’s common to produce many files per second.
0

Easy Function in C#:

public static string GetTempFileName(string extension = "csv")
{
 return Path.ChangeExtension(Path.GetTempFileName(), extension);
}
answered Feb 6, 2019 at 19:19

4 Comments

GetTempFileName() creates a temporary file in the temp folder. As a result you will have two temporary files created, one of which will leak.
@evgenybf , We are not creating two files. We are generating a file then changing the extension.
you are wrong. Check out the documentation: learn.microsoft.com/en-us/dotnet/api/… GetTempFileName() creates a file and returns its name. Then, you take its name and change its extension. But it only affects the string name, not the name of the physical file on the disc. Then you return the modified name, leaving temporary file on the disc forgotten.
Call the method several times and look into your %TEMP% directory. There will be many empty .tmp files there. After a while, when there are too many tmp files (>~60k), GetTempFileName() will start throwing IOException "The file exists".
0

In this what we can do we can first find the extension of file which is coming from file and after finding its extension.Then we can create the temprary name of file and after that we can change extension by the previous one it will works.

var name = Path.GetTempFileName();
var changename = Path.GetFileName(name);
var fileName = Path.ChangeExtension(changename, fileExtension);
Esset
1,0562 gold badges16 silver badges18 bronze badges
answered Jan 5, 2023 at 7:43

Comments

-2

I think you should try this:

string path = Path.GetRandomFileName();
path = Path.Combine(@"c:\temp", path);
path = Path.ChangeExtension(path, ".tmp");
File.Create(path);

It generates a unique filename and creates a file with that file name at a specified location.

McDowell
109k31 gold badges207 silver badges272 bronze badges
answered Aug 22, 2011 at 7:16

1 Comment

This solution has so many problems with it. you can't combine C:\temp with an absolute path, c:\temp may not be writeable, and it doesn't guarantee that the .tmp version of the file is unique.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.