سؤال

أنا أعمل على برنامج يحتاج إلى إنشاء مجلدات مؤقتة متعددة للتطبيق.لن يراها المستخدم.التطبيق مكتوب بلغة VB.net.يمكنني التفكير في عدة طرق للقيام بذلك مثل اسم المجلد المتزايد أو أسماء المجلدات المرقمة بشكل عشوائي، لكنني كنت أتساءل، كيف يحل الأشخاص الآخرون هذه المشكلة؟

هل كانت مفيدة؟

المحلول

تحديث: تمت إضافة الملف. يوجد فحص لكل تعليق (2012 يونيو 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:\المستندات والإعدادات\اسم المستخدم\الإعدادات المحلية emp\u3z5e0co.tvq


فيما يلي صيغة مختلفة تستخدم المرشد للحصول على اسم المجلد المؤقت.

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:\المستندات والإعدادات\اسم المستخدم\الإعدادات المحلية emp\2dbc6db7-2d45-4b75-b27f-0bd492c60496

نصائح أخرى

عليك أن تستخدم System.IO.Path.GetTempFileName()

يقوم بإنشاء ملف مؤقت ذو اسم فريد على القرص وإرجاع المسار الكامل لذلك الملف.

يمكنك استخدام System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()) للحصول على معلومات المجلد المؤقت فقط، وإنشاء المجلدات الخاصة بك هناك

يتم إنشاؤها في مجلد windows temp وهذا يعتبر من أفضل الممارسات

فقط للتوضيح:

System.IO.Path.GetTempPath()

يقوم بإرجاع مسار المجلد فقط إلى المجلد المؤقت.

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 Shell، يعد إنشاء ملفات وأدلة مؤقتة بطريقة آمنة وخالية من أي سباق أمرًا مهمًا.تحتوي العديد من الأجهزة على العديد من المستخدمين (المعاديين) - فكر في مضيف الويب المشترك - وتحتاج العديد من البرامج النصية والتطبيقات إلى إنشاء ملفات وأدلة مؤقتة بأمان في الدليل /tmp المشترك.يرى إنشاء ملفات مؤقتة بأمان في البرامج النصية لـ Shell لمناقشة كيفية إنشاء أدلة مؤقتة بأمان من نصوص shell النصية.

مثل @ جوناثان رايت أشار, ، شروط السباق موجودة للحلول:

  • قم بإنشاء ملف مؤقت باستخدام GetTempFileName(), وحذفه وإنشاء مجلد بنفس الاسم
  • يستخدم GetRandomFileName() أو Guid.NewGuid.ToString لإنشاء اسم مجلد عشوائي، تحقق مما إذا كان موجودًا، وقم بإنشائه إذا لم يكن كذلك.

ومع ذلك، من الممكن إنشاء دليل مؤقت فريد ذريًا باستخدام ملف المعاملات NTFS (تكسف) API.

TxF لديه CreateDirectoryTransacted() الوظيفة التي يمكن استدعاؤها عبر استدعاء النظام الأساسي.للقيام بذلك، تكيفت كود محمد الشيمي للاتصال 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());
}

شيء مثل...

using System.IO;

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

Directory.CreateDirectory(path);

يمكنك إنشاء GUID لأسماء المجلدات المؤقتة الخاصة بك.

طالما أن اسم المجلد لا يلزم أن يكون ذا معنى، فماذا عن استخدام المعرف الفريد العمومي (GUID) له؟

يمكنك استخدام GetTempFileName لإنشاء مؤقت ملف, ، ثم قم بحذف هذا الملف وإعادة إنشائه كدليل بدلاً من ذلك.

ملحوظة:الرابط لا يعمل، انسخ/لصق من: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

الإجابات المجمعة من @adam-wright وpix0r ستعمل بشكل أفضل على IMHO:


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 في أنه سيكون ملفًا في المسار المحلي (أي غير المتجول) للمستخدم.هذا هو بالضبط المكان الذي تريده للأذونات ولأسباب أمنية.

Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))

يقترحJonathanWright أن برنامج CreateDirectory سيفشل عندما يكون هناك مجلد بالفعل.إذا قرأت الدليل. createdirectory ، فإنه يقول "يتم إرجاع هذا الكائن بغض النظر عما إذا كان هناك دليل في المسار المحدد موجودًا بالفعل". وهذا يعني أنك لا تكتشف مجلد تم إنشاؤه بين الشيك وإنشاء بالفعل.

تعجبني وظيفة CreateDirectoryTransacted() التي اقترحها @DanielTrebbien ولكن تم إهمال هذه الوظيفة.

الحل الوحيد الذي أرى أنه متبقي هو استخدام واجهة برمجة تطبيقات c واستدعاء "إنشاء دليلهناك خطأ في حالة وجود المجلد إذا كنت بحاجة حقًا إلى التأكد من تغطية حالة السباق بالكامل.سيؤدي ذلك إلى شيء مثل هذا:

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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top