Я работаю над программой, которая должна создать несколько временных папок для приложения. Они не будут видны пользователю. Приложение написано на VB.net. Я могу подумать о нескольких способах сделать это, таких как добавочное имя папки или случайное нумерованное имя папки, но мне было интересно, как другие люди решают эту проблему?
Обновление: добавлена проверка File.Exists за комментарий (2012-Jun-19)
Вот что я использовал в VB.NET. По сути, то же самое, что представлено, за исключением того, что я обычно не хотел создавать папку немедленно.
Преимущество использования GetRandomFilename заключается в том, что он не создает файл, поэтому вам не нужно выполнять очистку, если вы используете имя для чего-то, кроме файла. Как использовать его для имени папки.
Private Function GetTempFolder() As String
Dim folder As String = Path.Combine(Path.GetTempPath, Path.GetRandomFileName)
Do While Directory.Exists(folder) or File.Exists(folder)
folder = Path.Combine(Path.GetTempPath, Path.GetRandomFileName)
Loop
Return folder
End Function
Случайное имя файла Пример:
C: \ Documents and Settings \ имя пользователя \ Локальные настройки \ Temp \ u3z5e0co.tvq
Вот вариант с использованием Guid для получения имени временной папки.
Private Function GetTempFolderGuid() As String
Dim folder As String = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString)
Do While Directory.Exists(folder) or File.Exists(folder)
folder = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString)
Loop
Return folder
End Function
Пример guid :
C: \ Documents and Settings \ имя пользователя \ Локальные настройки \ Temp \ 2dbc6db7-2d45-4b75-b27f-0bd492c60496
Пока имя папки не должно быть значимым, как насчет использования GUID для них?
Вы можете сгенерировать GUID для ваших имен временных папок.
Вы можете использовать GetTempFileName для создания временного файла , а затем удалить и заново создать этот файл как каталог.
Примечание: ссылка не работает, скопируйте / вставьте с: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx
Вы должны использовать System.IO.Path.GetTempFileName()
Создает на диске временный файл с нулевым байтом с уникальным именем и возвращает полный путь к этому файлу.
Вы можете использовать, System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName())
чтобы получить только информацию о временной папке, и создавать там свои папки
Они создаются во временной папке Windows, и это считается наилучшей практикой
System.IO.Path.GetDirectoryName
на System.IO.Path.GetTempFileName
худшую для замены System.IO.Path.GetTempPath
, так как он создает файл , который получает остался позади. Что-то типа...
using System.IO;
string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
path = Path.GetTempPath() + Path.GetRandomFileName();
Directory.CreateDirectory(path);
Объединенные ответы от @ adam-wright и pix0r будут работать лучше всего ИМХО:
using System.IO;
string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
path = Path.GetTempPath() + Path.GetRandomFileName();
File.Delete(path);
Directory.CreateDirectory(path);
Преимущество использования System.IO.Path.GetTempFileName заключается в том, что это будет файл с локальным (т. Е. Не роуминг) путем пользователя. Это именно то место, где вы хотели бы получить разрешения и соображения безопасности.
Чтобы уточнить:
System.IO.Path.GetTempPath()
возвращает только путь к папке temp.
System.IO.Path.GetTempFileName()
возвращает полное имя файла (включая путь), вот так:
System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName())
избыточно
Возможны условия гонки, когда:
- создание временного файла с
GetTempFileName()
его удалением и создание папки с тем же именем, или - используя
GetRandomFileName()
илиGuid.NewGuid.ToString
для имени папки и создания папки позже
После GetTempFileName()
удаления другое приложение может успешно создать временный файл с тем же именем. Тогда CreateDirectory()
бы не получилось.
Аналогично, между вызовом GetRandomFileName()
и созданием каталога другой процесс может создать файл или каталог с тем же именем, что снова приведет к CreateDirectory()
сбою.
Для большинства приложений это нормально, если временный каталог не работает из-за состояния гонки. Это чрезвычайно редко в конце концов. Для них эти гонки часто можно игнорировать.
В мире сценариев оболочки Unix создание временных файлов и каталогов безопасным способом без гонок является большой проблемой. У многих машин есть несколько (враждебных) пользователей - например, общий веб-хост - и многие сценарии и приложения должны безопасно создавать временные файлы и каталоги в каталоге shared / tmp. См. Безопасное создание временных файлов в сценариях оболочки для обсуждения того, как безопасно создавать временные каталоги из сценариев оболочки.
Как отметил @JonathanWright , для решений существуют условия гонки:
- Создайте временный файл
GetTempFileName()
, удалите его и создайте папку с тем же именем - Используйте
GetRandomFileName()
илиGuid.NewGuid.ToString
для создания произвольного имени папки, проверьте, существует ли оно, и создайте его, если нет.
Тем не менее, можно создать уникальный временный каталог атомарно, используя Transactional NTFS (TxF) API.
TxF имеет CreateDirectoryTransacted()
функцию, которая может быть вызвана через Platform Invoke. Для этого я адаптировал код Мохаммада Эльсхейми для вызова CreateFileTransacted()
:
// using System.ComponentModel;
// using System.Runtime.InteropServices;
// using System.Transactions;
[ComImport]
[Guid("79427a2b-f895-40e0-be79-b57dc82ed231")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IKernelTransaction
{
void GetHandle(out IntPtr pHandle);
}
// 2.2 Win32 Error Codes <http://msdn.microsoft.com/en-us/library/cc231199.aspx>
public const int ERROR_PATH_NOT_FOUND = 0x3;
public const int ERROR_ALREADY_EXISTS = 0xb7;
public const int ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION = 0x1aaf;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool CreateDirectoryTransacted(string lpTemplateDirectory, string lpNewDirectory, IntPtr lpSecurityAttributes, IntPtr hTransaction);
/// <summary>
/// Creates a uniquely-named directory in the directory named by <paramref name="tempPath"/> and returns the path to it.
/// </summary>
/// <param name="tempPath">Path of a directory in which the temporary directory will be created.</param>
/// <returns>The path of the newly-created temporary directory within <paramref name="tempPath"/>.</returns>
public static string GetTempDirectoryName(string tempPath)
{
string retPath;
using (TransactionScope transactionScope = new TransactionScope())
{
IKernelTransaction kernelTransaction = (IKernelTransaction)TransactionInterop.GetDtcTransaction(Transaction.Current);
IntPtr hTransaction;
kernelTransaction.GetHandle(out hTransaction);
while (!CreateDirectoryTransacted(null, retPath = Path.Combine(tempPath, Path.GetRandomFileName()), IntPtr.Zero, hTransaction))
{
int lastWin32Error = Marshal.GetLastWin32Error();
switch (lastWin32Error)
{
case ERROR_ALREADY_EXISTS:
break;
default:
throw new Win32Exception(lastWin32Error);
}
}
transactionScope.Complete();
}
return retPath;
}
/// <summary>
/// Equivalent to <c>GetTempDirectoryName(Path.GetTempPath())</c>.
/// </summary>
/// <seealso cref="GetTempDirectoryName(string)"/>
public static string GetTempDirectoryName()
{
return GetTempDirectoryName(Path.GetTempPath());
}
Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))
@JonathanWright предлагает создать CreateDirectory, если папка уже есть. Если я читаю Directory.CreateDirectory, он говорит: «Этот объект возвращается независимо от того, существует ли каталог по указанному пути». Это означает, что вы не обнаруживаете папку, созданную между проверкой, существует и фактически создает.
Мне нравится CreateDirectoryTransacted (), предложенный @DanielTrebbien, но эта функция устарела.
Единственное оставшееся решение, которое я вижу, - это использовать c api и вызывать там « CreateDirectory », так как это приводит к ошибке, если папка существует, если вам действительно нужно быть уверенным, что она покрывает все условия гонки. Это приведет к чему-то вроде этого:
Private Function GetTempFolder() As String
Dim folder As String
Dim succes as Boolean = false
Do While not succes
folder = Path.Combine(Path.GetTempPath, Path.GetRandomFileName)
success = c_api_create_directory(folder)
Loop
Return folder
End Function
File.Exists
в дополнение кDirectory.Exists
? Там может быть существующий темп файла вPath.GetTempPath
, и что будет препятствовать созданию каталога.Imports System.IO