Как создать временный файл с определенным расширением with.NET?
Мне нужно создать уникальный временный файл с a .расширение csv.
то, что я делаю прямо сейчас, это
string filename = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");
однако, это не гарантирует, что моей .csv-файл будет уникальным.
Я знаю, что шансы я когда-либо получил столкновение очень низки (особенно если вы считаете, что я не удаляю .tmp файлы), но этот код не выглядит хорошо для меня.
конечно, я мог бы вручную генерировать случайные имена файлов, пока я в конечном итоге не найду уникальный (что не должно быть проблемой), но мне любопытно узнать, нашли ли другие хороший способ справиться с этой проблемой.
14 ответов:
гарантированно будет (статистически) уникально:
string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
(цитата из статьи wiki о вероятности столкновения:
...ежегодный риск попадания метеорит оценивается в один шанс в 17 миллиардов [19], что означает вероятность составляет около 0.00000000006 (6 × 10-11), эквивалентные коэффициентам создание нескольких десятков триллионов UUIDs в год и имея один дубликат. Другими словами, только после генерации 1 млрд идентификаторы UUID каждый во-вторых, в течение следующих 100 лет вероятность создания только одного дубликат будет около 50%. Этот вероятность одного дубликата была бы около 50% если каждый человек на земле владеет 600 млн UUIDs
EDIT: пожалуйста, Также см. комментарии JaredPar.
попробовать эту функцию ...
public static string GetTempFilePathWithExtension(string extension) { var path = Path.GetTempPath(); var fileName = Guid.NewGuid().ToString() + extension; return Path.Combine(path, fileName); }
он вернет полный путь с расширением по вашему выбору.
обратите внимание, что не гарантируется создание уникального имени файла, так как кто-то другой мог технически уже создать этот файл. Однако вероятность того, что кто-то угадает следующий guid, созданный вашим приложением, и создаст его, очень мала. Это довольно безопасно предположить, что это будет уникальным.
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); } } }
Примечание: это работает, как путь.GetTempFileName. Для резервирования имени файла создается пустой файл. Он делает 10 попыток, в случае столкновений, генерируемых Path.GetRandomFileName ();
документация MSDN для в C++'GetTempFileName ы обсуждает вашу озабоченность и отвечает на нее:
GetTempFileName не может гарантировать, что имя файла уникально.
используются только младшие 16 бит параметра uUnique. Это ограничивает GetTempFileName до 65 535 уникальных имен файлов, если параметры lpPathName и lpPrefixString остаются неизменными.
из-за алгоритма, используемого для генерация имен файлов, GetTempFileName может работать плохо при создании большого количества файлов с одним и тем же префиксом. В таких случаях рекомендуется создавать уникальные имена файлов на основе идентификаторов GUID.
почему бы не проверить, если файл существует?
string fileName; do { fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv"; } while (System.IO.File.Exists(fileName));
Как насчет:
Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".csv")
крайне маловероятно, что компьютер будет генерировать один и тот же идентификатор Guid в один и тот же момент времени. Единственная слабость, которую я вижу здесь, - это влияние на производительность DateTime.Сейчас.Клещей будет добавить.
вы также можете сделать следующее
string filename = Path.ChangeExtension(Path.GetTempFileName(), ".csv");
и это также работает, как ожидалось
string filename = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");
на мой взгляд, большинство ответов предлагается здесь как неоптимальные. Наиболее близким является оригинал, предложенный первоначально Бранном.
имя файла Temp должно быть
- уникальный
- бесконфликтный (еще не существует)
- Atomic (создание имени и файла в одной операции)
- трудно догадаться
из-за этих требований, это не идея Бога, чтобы запрограммировать такого зверя самостоятельно. умные люди написание библиотек ИО беспокоиться о таких вещах, как запирание (при необходимости) и т. д. Поэтому я не вижу необходимости переписывать 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);
Это может быть удобно для вас... Это для того, чтобы создать темп. папка и вернуть его в виде строки в VB.NET.
легко конвертируется в 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
это, кажется, работает нормально для меня: он проверяет наличие файла и создает файл, чтобы убедиться, что это место для записи. Должно работать нормально, вы можете изменить его, чтобы вернуть непосредственно 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
вот что я делаю:
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";
Это простой, но эффективный способ создания добавочной имена. Он будет искать в текущем непосредственно (вы можете легко указать, что где-то еще) и искать файлы с базой YourApplicationName*.тхт (вы можете легко изменить это). Он начнется в 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; }