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

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

8 ответов


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

вам понадобится код, подобный этому:

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

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

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

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

  return tempFolder;
}

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


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

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


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

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

    [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 () остается в качестве упражнения для студента. Я использую каталог.CreateDirectory(). Будьте осторожны с получением родительского каталога, так как он имеет значение null в корневом каталоге.


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


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

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

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);

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

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


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

    /// <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;
    }

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

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