Создание временного каталога в Windows?

Какой лучший способ получить имя временного каталога в Windows? Я вижу, что я могу использовать GetTempPath и GetTempFileName для создания временного файла, но есть ли какой-либо эквивалент Linux/BSD mkdtemp для создания временного каталога?

Ответ 1

Нет, нет эквивалента mkdtemp. Лучшим вариантом является использование комбинации GetTempPath и GetRandomFileName.

Вам понадобится код, похожий на этот:

public string GetTemporaryDirectory()
{
   string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
   Directory.CreateDirectory(tempDirectory);
   return tempDirectory;
}

Ответ 2

Я взломаю Path.GetTempFileName(), чтобы дать мне действительный псевдослучайный путь к файлу на диске, затем удалить файл и создать каталог с тем же путем.

Это позволяет избежать необходимости проверять, доступен ли путь к файлу через время или цикл, на комментарий Криса относительно ответа Скотта Дормана.

public string GetTemporaryDirectory()
{
  string tempFolder = Path.GetTempFileName();
  File.Delete(tempFolder);
  Directory.CreateDirectory(tempFolder);

  return tempFolder;
}

Если вам действительно нужно криптографически безопасное случайное имя, вам может понадобиться адаптировать ответ Скотта, чтобы использовать какое-то время или сделать цикл, чтобы попытаться создать путь на диске.

Ответ 3

Мне нравится использовать GetTempPath(), функцию создания GUID, такую ​​как CoCreateGuid() и CreateDirectory().

GUID предназначен для высокой вероятности уникальности, а также очень маловероятно, что кто-то вручную создавал каталог с той же формой, что и GUID (и если они это сделают, то CreateDirectory() не сможет указать его существование).

Ответ 4

GetTempPath - правильный способ сделать это; Я не уверен, что вы беспокоитесь об этом методе. Вы можете использовать CreateDirectory, чтобы сделать это.

Ответ 5

Вот несколько более грубый подход к решению проблемы столкновения для имен временных каталогов. Это не безошибочный подход, но он значительно снижает вероятность столкновения с траекторией папки.

Можно было бы добавить другую информацию, связанную с процессом или сборкой, в имя каталога, чтобы сделать столкновение еще менее вероятным, хотя такая информация, видимая во временном каталоге, может оказаться нежелательной. Можно также смешать порядок, с которым объединены связанные по времени поля, чтобы сделать имена папок более случайными. Я лично предпочитаю оставить это так просто, потому что мне легче найти их во время отладки.

string randomlyGeneratedFolderNamePart = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());

string timeRelatedFolderNamePart = DateTime.Now.Year.ToString()
                                 + DateTime.Now.Month.ToString()
                                 + DateTime.Now.Day.ToString()
                                 + DateTime.Now.Hour.ToString()
                                 + DateTime.Now.Minute.ToString()
                                 + DateTime.Now.Second.ToString()
                                 + DateTime.Now.Millisecond.ToString();

string processRelatedFolderNamePart = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();

string temporaryDirectoryName = Path.Combine( Path.GetTempPath()
                                            , timeRelatedFolderNamePart 
                                            + processRelatedFolderNamePart 
                                            + randomlyGeneratedFolderNamePart);

Ответ 6

@Крис. Я тоже был одержим удаленным риском того, что временная директория может уже существовать. Дискуссии о случайных и криптографически сильных не полностью удовлетворяют меня.

Мой подход основывается на фундаментальном факте, что O/S не позволяет двум вызовам создать файл для обоих. Немного удивительно, что разработчики .NET решили скрыть функциональность API Win32 для каталогов, что делает это намного проще, поскольку оно возвращает ошибку при попытке создать каталог во второй раз. Вот что я использую:

    [DllImport(@"kernel32.dll", EntryPoint = "CreateDirectory", SetLastError = true, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CreateDirectoryApi
        ([MarshalAs(UnmanagedType.LPTStr)] string lpPathName, IntPtr lpSecurityAttributes);

    /// <summary>
    /// Creates the directory if it does not exist.
    /// </summary>
    /// <param name="directoryPath">The directory path.</param>
    /// <returns>Returns false if directory already exists. Exceptions for any other errors</returns>
    /// <exception cref="System.ComponentModel.Win32Exception"></exception>
    internal static bool CreateDirectoryIfItDoesNotExist([NotNull] string directoryPath)
    {
        if (directoryPath == null) throw new ArgumentNullException("directoryPath");

        // First ensure parent exists, since the WIN Api does not
        CreateParentFolder(directoryPath);

        if (!CreateDirectoryApi(directoryPath, lpSecurityAttributes: IntPtr.Zero))
        {
            Win32Exception lastException = new Win32Exception();

            const int ERROR_ALREADY_EXISTS = 183;
            if (lastException.NativeErrorCode == ERROR_ALREADY_EXISTS) return false;

            throw new System.IO.IOException(
                "An exception occurred while creating directory'" + directoryPath + "'".NewLine() + lastException);
        }

        return true;
    }

Вы можете решить, стоит ли "стоимость/риск" неуправляемого кода p/invoke. Большинство бы сказали, что это не так, но по крайней мере у вас теперь есть выбор.

CreateParentFolder() остается как упражнение для ученика. Я использую Directory.CreateDirectory(). Будьте осторожны, получая родительский каталог, поскольку он имеет значение null, когда находится в корне.

Ответ 7

Как упоминалось выше, Path.GetTempPath() - это один из способов сделать это. Вы также можете вызвать Environment.GetEnvironmentVariable( "TEMP" ), если у пользователя установлена ​​переменная среды TEMP.

Если вы планируете использовать временную директорию как средство сохранения данных в приложении, вы, вероятно, должны посмотреть на IsolatedStorage как репозиторий для конфигурации/состояния/etc...

Ответ 8

Я обычно использую это:

    /// <summary>
    /// Creates the unique temporary directory.
    /// </summary>
    /// <returns>
    /// Directory path.
    /// </returns>
    public string CreateUniqueTempDirectory()
    {
        var uniqueTempDir = Path.GetFullPath(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
        Directory.CreateDirectory(uniqueTempDir);
        return uniqueTempDir;
    }

Если вы хотите быть абсолютно уверены, что это имя каталога не будет существовать в temp-пути, вам нужно проверить, существует ли это уникальное имя каталога и пытаться создать другое, если оно действительно существует.

Но эта реализация на основе GUID достаточно. В этом случае у меня нет никаких проблем с какой-либо проблемой. Некоторые приложения MS также используют временные каталоги, основанные на GUID.