I need to generate a unique temporary file with a .csv extension.
我需要生成一个带有.csv扩展名的唯一临时文件。
What I do right now is
我现在做的是
string filename = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");
However, this doesn't guarantee that my .csv file will be unique.
然而,这并不能保证我的.csv文件是唯一的。
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.
我知道发生冲突的可能性非常低(特别是如果您认为我没有删除.tmp文件),但是这段代码对我来说并不好。
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.
当然,我可以手工生成随机文件名,直到我最终找到一个唯一的文件名(这应该不是问题),但是我很想知道其他人是否找到了解决这个问题的好方法。
14 个解决方案
#1
284
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
…一个年度的风险被陨石击中估计在170亿年一次机会[19],这意味着概率是0.00000000006(6×10−11),相当于创建的几率几数以万亿的uuid一年,有一个重复的。换句话说,在接下来的100年里,每秒钟产生10亿个uuid,产生一个副本的概率大约是50%。如果地球上的每个人都拥有6亿个uuid,那么一个副本的概率大约是50%
EDIT: Please also see JaredPar's comments.
编辑:请查看JaredPar的评论。
#2
43
Try this function ...
试试这个功能……
public static string GetTempFilePathWithExtension(string extension) {
var path = Path.GetTempPath();
var fileName = 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.
注意,它不能保证生成唯一的文件名,因为从技术上讲,其他人可能已经创建了该文件。然而,有人猜测你的应用生成的下一个guid并创建它的几率非常低。可以很有把握地假设这是唯一的。
#3
36
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();
注意:这类似于Path.GetTempFileName。创建一个空文件来保留文件名。如果路径. getrandomfilename()产生冲突,则执行10次尝试;
#4
17
You can also alternatively use System.CodeDom.Compiler.TempFileCollection.
您还可以使用system . codedom.compile . 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.
这里我使用了txt扩展,但你可以指定任何你想要的。我还将keep标志设置为true,以便在使用后保留临时文件。不幸的是,TempFileCollection每扩展创建一个随机文件。如果需要更多的临时文件,可以创建多个TempFileCollection实例。
#5
8
The MSDN documentation for C++'s GetTempFileName discusses your concern and answers it:
c++ GetTempFileName的MSDN文档讨论您的关注并回答它:
GetTempFileName is not able to guarantee that the file name is unique.
GetTempFileName不能保证文件名是唯一的。
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.
只使用uUnique参数的低16位。如果lpPathName和lpPrefixString参数保持不变,则将GetTempFileName限制为最大65,535个唯一文件名。
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.
由于用于生成文件名的算法,当创建大量具有相同前缀的文件时,GetTempFileName的性能很差。在这种情况下,建议您基于gui构造惟一的文件名。
#6
6
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));
#7
5
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.
计算机在同一时刻生成相同的Guid是极不可能的。我在这里看到的惟一缺点是性能影响日期时间。蜱虫会增加。
#8
4
You can also do the following
您还可以执行以下操作
string filename = Path.ChangeExtension(Path.GetTempFileName(), ".csv");
and this also works as expected
这也和预期的一样
string filename = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
#9
3
In my opinion, most answers proposed here as sub-optimal. The one coming closest is the original one proposed initially by Brann.
在我看来,这里提出的大多数答案都是次优的。最接近的是最初由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().
由于这些要求,用你自己的方式来编写这样一个怪物并不是一个godd的主意。编写IO库的聪明人担心锁(如果需要)等问题。因此,我认为没有必要重写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);
#10
2
This could be handy for you... It's to create a temp. folder and return it as a string in VB.NET.
这对你来说很方便……它将创建一个temp.文件夹并将它作为VB.NET中的一个字符串返回。
Easily convertible to C#:
容易对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
#11
2
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):
这对我来说似乎没问题:它检查文件存在,并创建文件以确保它是可写的位置。如果工作正常,您可以将其更改为直接返回FileStream(这通常是您需要的临时文件):
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
#12
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";
#13
0
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.
这是生成增量文件名的一种简单而有效的方法。它将直接查找当前(您可以很容易地指向其他地方),并使用基本的YourApplicationName*搜索文件。txt(同样可以很容易地更改它)。它将从0000开始,因此第一个文件名将是您的applicationname0000.txt。如果由于某种原因,在左右部分之间(意思不是数字)有垃圾文件名称,那么这些文件将由于tryparse调用而被忽略。
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;
}
#14
-1
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.
它生成一个唯一的文件名,并在指定位置创建一个文件名为该文件名的文件。
#1
284
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
…一个年度的风险被陨石击中估计在170亿年一次机会[19],这意味着概率是0.00000000006(6×10−11),相当于创建的几率几数以万亿的uuid一年,有一个重复的。换句话说,在接下来的100年里,每秒钟产生10亿个uuid,产生一个副本的概率大约是50%。如果地球上的每个人都拥有6亿个uuid,那么一个副本的概率大约是50%
EDIT: Please also see JaredPar's comments.
编辑:请查看JaredPar的评论。
#2
43
Try this function ...
试试这个功能……
public static string GetTempFilePathWithExtension(string extension) {
var path = Path.GetTempPath();
var fileName = 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.
注意,它不能保证生成唯一的文件名,因为从技术上讲,其他人可能已经创建了该文件。然而,有人猜测你的应用生成的下一个guid并创建它的几率非常低。可以很有把握地假设这是唯一的。
#3
36
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();
注意:这类似于Path.GetTempFileName。创建一个空文件来保留文件名。如果路径. getrandomfilename()产生冲突,则执行10次尝试;
#4
17
You can also alternatively use System.CodeDom.Compiler.TempFileCollection.
您还可以使用system . codedom.compile . 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.
这里我使用了txt扩展,但你可以指定任何你想要的。我还将keep标志设置为true,以便在使用后保留临时文件。不幸的是,TempFileCollection每扩展创建一个随机文件。如果需要更多的临时文件,可以创建多个TempFileCollection实例。
#5
8
The MSDN documentation for C++'s GetTempFileName discusses your concern and answers it:
c++ GetTempFileName的MSDN文档讨论您的关注并回答它:
GetTempFileName is not able to guarantee that the file name is unique.
GetTempFileName不能保证文件名是唯一的。
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.
只使用uUnique参数的低16位。如果lpPathName和lpPrefixString参数保持不变,则将GetTempFileName限制为最大65,535个唯一文件名。
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.
由于用于生成文件名的算法,当创建大量具有相同前缀的文件时,GetTempFileName的性能很差。在这种情况下,建议您基于gui构造惟一的文件名。
#6
6
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));
#7
5
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.
计算机在同一时刻生成相同的Guid是极不可能的。我在这里看到的惟一缺点是性能影响日期时间。蜱虫会增加。
#8
4
You can also do the following
您还可以执行以下操作
string filename = Path.ChangeExtension(Path.GetTempFileName(), ".csv");
and this also works as expected
这也和预期的一样
string filename = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
#9
3
In my opinion, most answers proposed here as sub-optimal. The one coming closest is the original one proposed initially by Brann.
在我看来,这里提出的大多数答案都是次优的。最接近的是最初由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().
由于这些要求,用你自己的方式来编写这样一个怪物并不是一个godd的主意。编写IO库的聪明人担心锁(如果需要)等问题。因此,我认为没有必要重写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);
#10
2
This could be handy for you... It's to create a temp. folder and return it as a string in VB.NET.
这对你来说很方便……它将创建一个temp.文件夹并将它作为VB.NET中的一个字符串返回。
Easily convertible to C#:
容易对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
#11
2
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):
这对我来说似乎没问题:它检查文件存在,并创建文件以确保它是可写的位置。如果工作正常,您可以将其更改为直接返回FileStream(这通常是您需要的临时文件):
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
#12
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";
#13
0
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.
这是生成增量文件名的一种简单而有效的方法。它将直接查找当前(您可以很容易地指向其他地方),并使用基本的YourApplicationName*搜索文件。txt(同样可以很容易地更改它)。它将从0000开始,因此第一个文件名将是您的applicationname0000.txt。如果由于某种原因,在左右部分之间(意思不是数字)有垃圾文件名称,那么这些文件将由于tryparse调用而被忽略。
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;
}
#14
-1
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.
它生成一个唯一的文件名,并在指定位置创建一个文件名为该文件名的文件。