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


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

8 95

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

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

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

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