Создание временных папок

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
30
0
27 649
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Если имя папки не должно иметь смысла, как насчет использования для них GUID?

Вы можете создать GUID для имен ваших временных папок.

Вы можете использовать GetTempFileName для создания временного файл, а затем вместо этого удалить и воссоздать этот файл как каталог.

Примечание: ссылка не работает, скопируйте / вставьте из: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

Вы должны использовать System.IO.Path.GetTempFileName()

Creates a uniquely named, zero-byte temporary file on disk and returns the full path of that file.

Вы можете использовать System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()), чтобы получить только информацию о временной папке и создать там свои папки.

Они создаются во временной папке Windows, и это считается лучшей практикой.

Сделайте это НЕТ. Вызов System.IO.Path.GetDirectoryName на System.IO.Path.GetTempFileName - худшая замена System.IO.Path.GetTempPath, поскольку при этом создается файл, который остается позади.

Jaykul 30.03.2017 05:08

Что-то вроде...

using System.IO;

string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
 path = Path.GetTempPath() + Path.GetRandomFileName();

Directory.CreateDirectory(path);

возможно, с помощью try-catch, чтобы повторно войти в цикл, если вы не можете создать каталог ;-)

Jaykul 30.03.2017 05:12

ИМХО, лучше всего подойдут комбинированные ответы от @ 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 заключается в том, что это будет файл по локальному (т. Е. Не роуминговому) пути пользователя. Это именно то место, где вы хотели бы получить разрешения и из соображений безопасности.

Ответ принят как подходящий

Обновлять: Добавлена ​​проверка наличия файла на комментарий (19 июня 2012 г.)

Вот что я использовал в 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 \ имя пользователя \ Local 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

гид Пример:

C: \ Documents and Settings \ имя пользователя \ Local Settings \ Temp \ 2dbc6db7-2d45-4b75-b27f-0bd492c60496

Разве ваше условие цикла не должно включать File.Exists в дополнение к Directory.Exists? В Path.GetTempPath может существовать временный файл, и это помешает созданию каталога.

William Gross 18.06.2012 19:10

Ты прав. Я обновлю ответ, включив проверку File.Exists ()

Rick 20.06.2012 08:11

Вы должны Создайте для папки внутри функции - по той же причине, по которой GetTempFileName создает файл: чтобы убедиться, что нет никаких шансов, что это сделает кто-то другой.

Jaykul 30.03.2017 05:10

Не забудьте сделать Imports System.IO

Richie Bendall 22.06.2018 10:24

Просто для ясности:

System.IO.Path.GetTempPath()

возвращает только путь к папке temp.

System.IO.Path.GetTempFileName()

возвращает полное имя файла (включая путь), так что это:

System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName())

является избыточным.

GetTempPath и GetTempFileName - это 2 совершенно разных метода. GetTempPath просто возвращает местоположение временной папки системы, а GetTempFileName создает временный файл нулевой длины и возвращает полный путь к этому файлу.

Dries Van Hansewijck 14.12.2010 13:04

Возможное состояние гонки, когда:

  • создание временного файла с помощью GetTempFileName(), его удаление и создание папки с тем же именем, или
  • использование GetRandomFileName() или Guid.NewGuid.ToString для присвоения имени папке и последующего создания папки

С GetTempFileName() после удаления другое приложение могло успешно создать временный файл с тем же именем. Тогда CreateDirectory() выйдет из строя.

Точно так же между вызовом GetRandomFileName() и созданием каталога другой процесс может создать файл или каталог с тем же именем, что снова приведет к сбою CreateDirectory().

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

В мире сценариев оболочки Unix создание временных файлов и каталогов безопасным способом, исключающим гонку, является большим делом. На многих машинах есть несколько (враждебных) пользователей - подумайте об общем веб-хосте - и многим скриптам и приложениям необходимо безопасно создавать временные файлы и каталоги в общем каталоге / tmp. См. Безопасное создание временных файлов в сценариях оболочки для обсуждения того, как безопасно создавать временные каталоги из сценариев оболочки.

Как @JonathanWright указал, для решений существуют условия гонки:

  • Создайте временный файл с GetTempFileName(), удалите его и создайте папку с тем же именем.
  • Используйте GetRandomFileName() или Guid.NewGuid.ToString для создания случайного имени папки, проверьте, существует ли оно, и создайте его, если нет.

Однако возможно создать уникальный временный каталог атомарно, используя API Транзакционная NTFS (TxF).

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, он говорит: «Этот объект возвращается независимо от того, существует ли уже каталог по указанному пути». Это означает, что вы не обнаруживаете папку, созданную между проверкой существования и фактическим созданием.

Мне нравится CreateDirectoryTranscted (), предложенный @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

Было бы разумно проверить бесконечное зацикливание.

Matt 09.11.2017 07:14

Другие вопросы по теме