Как создать временный файл с определенным расширением с .NET?
Мне нужно создать уникальный временный файл с расширением .csv.
То, что я делаю прямо сейчас,
string filename = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");
Однако это не гарантирует, что мой .csv файл будет уникальным.
Я знаю, что шансы, которые у меня когда-либо были на столкновении, очень низки (особенно если вы считаете, что я не удаляю файлы .tmp), но этот код мне не подходит.
Конечно, я мог бы вручную генерировать случайные имена файлов до тех пор, пока в конечном итоге не найду уникальную (что не должно быть проблемой), но мне любопытно узнать, нашли ли другие хороший способ справиться с этой проблемой.
Ответы
Ответ 1
Гарантировано быть (статистически) уникальным:
string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
(Цитата из статьи wiki о вероятности столкновения:
... один ежегодный риск попадания метеорит оценивается как один шанс в 17 миллиардов [19], это означает вероятность составляет около 0,00000000006 (6 × 10-11), что эквивалентно шансам создав несколько десятков триллионов UUID в год и один дублировать. Другими словами, только после генерируя 1 млрд. UUID второй в течение следующих 100 лет, вероятность создания только одного дубликат составит около 50%. вероятность того, что один дубликат будет около 50%, если каждый человек на земле владеет 600 миллионов UUIDs
EDIT: см. также комментарии JaredPar.
Ответ 2
Попробуйте эту функцию...
public static string GetTempFilePathWithExtension(string extension) {
var path = Path.GetTempPath();
var fileName = Guid.NewGuid().ToString() + extension;
return Path.Combine(path, fileName);
}
Он вернет полный путь с расширением по вашему выбору.
Обратите внимание, что это не гарантирует получение уникального имени файла, поскольку кто-то еще мог бы технически уже создать этот файл. Однако вероятность того, что кто-то угадывает следующий guid, созданный вашим приложением, и создавая его, очень низок. Это довольно безопасно предположить, что это будет уникальным.
Ответ 3
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);
}
}
}
Примечание: это работает как Path.GetTempFileName. Для сохранения имени файла создается пустой файл. Он делает 10 попыток, в случае коллизий, генерируемых Path.GetRandomFileName();
Ответ 4
Вы также можете использовать 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");
Здесь я использовал расширение txt, но вы можете указать, что хотите. Я также установил флаг keep true, чтобы временный файл сохранялся после использования. К сожалению, TempFileCollection создает один случайный файл на расширение. Если вам нужно больше файлов temp, вы можете создать несколько экземпляров TempFileCollection.
Ответ 5
Документация MSDN для С++ GetTempFileName обсуждает вашу проблему и отвечает на нее:
GetTempFileName не может гарантировать уникальность имени файла.
Используются только младшие 16 бит параметра uUnique. Это ограничивает GetTempFileName максимум 65535 уникальными именами файлов, если параметры lpPathName и lpPrefixString остаются неизменными.
Благодаря алгоритму, используемому для генерации имен файлов, GetTempFileName может плохо работать при создании большого количества файлов с одним и тем же префиксом. В таких случаях рекомендуется создавать уникальные имена файлов на основе GUID.
Ответ 6
Почему бы не проверить, существует ли файл?
string fileName;
do
{
fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
} while (System.IO.File.Exists(fileName));
Ответ 7
Как насчет:
Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".csv")
Очень маловероятно, что компьютер будет генерировать тот же Guid в тот же момент времени. Единственная слабость, которую я вижу здесь, - это влияние производительности DateTime.Now.Ticks будет добавлено.
Ответ 8
Вы также можете сделать следующее
string filename = Path.ChangeExtension(Path.GetTempFileName(), ".csv");
и это также работает как ожидалось
string filename = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
Ответ 9
На мой взгляд, большинство ответов, предложенных здесь как субоптимальные. Ближайший ближайший - это оригинал, первоначально предложенный Бранном.
Имя файла Temp должно быть
- Уникальный
- Без конфликтов (еще не существует)
- Atomic (создание имени и файла в той же операции)
- Трудно догадаться
Из-за этих требований, это не богиня, чтобы запрограммировать такого зверя самостоятельно. Умные люди, пишущие библиотеки IO, беспокоятся о таких вещах, как блокировка (при необходимости) и т.д.
Поэтому я не вижу необходимости переписывать System.IO.Path.GetTempFileName().
Это, даже если оно выглядит неуклюжим, должно выполнить эту задачу:
//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
Это может быть удобно для вас... Это создаст темп. и вернуть его в виде строки в VB.NET.
Легко конвертируется в С#:
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
Кажется, это работает отлично для меня: он проверяет наличие файла и создает файл, чтобы убедиться, что он доступен для записи.
Должен работать нормально, вы можете изменить его, чтобы напрямую вернуть 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
Это то, что я делаю:
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
Это простой, но эффективный способ создания дополнительных имен файлов. Он будет смотреть в текущем напрямую (вы можете легко указать это где-то еще) и искать файлы с базовым именем YourApplicationName *.txt (опять же, вы можете легко это изменить). Он начнется в 0000, поэтому первое имя файла будет YourApplicationName0000.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
Простая функция в С#:
public static string GetTempFileName(string extension = "csv")
{
return Path.ChangeExtension(Path.GetTempFileName(), extension);
}
Ответ 15
Думаю, вам стоит попробовать:
string path = Path.GetRandomFileName();
path = Path.Combine(@"c:\temp", path);
path = Path.ChangeExtension(path, ".tmp");
File.Create(path);
Он генерирует уникальное имя файла и создает файл с этим именем файла в указанном месте.