ج#:كيف يمكنك إنشاء اسم ملف فريد عن طريق إضافة رقم؟

StackOverflow https://stackoverflow.com/questions/1078003

  •  21-08-2019
  •  | 
  •  

سؤال

أرغب في إنشاء طريقة تأخذ إما اسم ملف كملف string أو أ FileInfo ويضيف رقمًا متزايدًا إلى اسم الملف إذا كان الملف موجودًا.لكن لا يمكنني أن أستوعب تمامًا كيفية القيام بذلك بطريقة جيدة.

على سبيل المثال، إذا كان لدي FileInfo

var file = new FileInfo(@"C:\file.ext");

أرغب في أن تعطيني الطريقة FileInfo جديدة باستخدام ج:\الملف 1.ext لو جيم:\ملف.extكانت موجودة، و ج:\الملف 2.ext لو ج:\الملف 1.ext كانت موجودة وهكذا.شيء من هذا القبيل:

public FileInfo MakeUnique(FileInfo fileInfo)
{
    if(fileInfo == null)
        throw new ArgumentNullException("fileInfo");
    if(!fileInfo.Exists)
        return fileInfo;

    // Somehow construct new filename from the one we have, test it, 
    // then do it again if necessary.
}
هل كانت مفيدة؟

المحلول 2

والكثير من النصائح الجيدة هنا. انتهى بي الأمر باستخدام طريقة كتبه مارك في <لأ href = "https://stackoverflow.com/questions / 909521 / الفنية إلى حل، تخزين القيم-persistenly من ملفات في واحد في دليل هذا مشكلة / 909545 # 909545 "> وردا على سؤال مختلفة . إخراجها منه القليل وأضاف طريقة أخرى لجعله أسهل قليلا لاستخدام "من الخارج". هنا هو النتيجة:

private static string numberPattern = " ({0})";

public static string NextAvailableFilename(string path)
{
    // Short-cut if already available
    if (!File.Exists(path))
        return path;

    // If path has extension then insert the number pattern just before the extension and return next filename
    if (Path.HasExtension(path))
        return GetNextFilename(path.Insert(path.LastIndexOf(Path.GetExtension(path)), numberPattern));

    // Otherwise just append the pattern to the path and return next filename
    return GetNextFilename(path + numberPattern);
}

private static string GetNextFilename(string pattern)
{
    string tmp = string.Format(pattern, 1);
    if (tmp == pattern)
        throw new ArgumentException("The pattern must include an index place-holder", "pattern");

    if (!File.Exists(tmp))
        return tmp; // short-circuit if no matches

    int min = 1, max = 2; // min is inclusive, max is exclusive/untested

    while (File.Exists(string.Format(pattern, max)))
    {
        min = max;
        max *= 2;
    }

    while (max != min + 1)
    {
        int pivot = (max + min) / 2;
        if (File.Exists(string.Format(pattern, pivot)))
            min = pivot;
        else
            max = pivot;
    }

    return string.Format(pattern, max);
}

وفقط اختبار جزئيا حتى الآن، ولكن سيتم تحديث إذا وجدت أي البق معها. ( مارك شفرة يعمل بشكل جيد!) إذا وجدت أي مشاكل معها، يرجى التعليق أو تحرير أو شيء :)

نصائح أخرى

public FileInfo MakeUnique(string path)
{            
    string dir = Path.GetDirectoryName(path);
    string fileName = Path.GetFileNameWithoutExtension(path);
    string fileExt = Path.GetExtension(path);

    for (int i = 1; ;++i) {
        if (!File.Exists(path))
            return new FileInfo(path);

        path = Path.Combine(dir, fileName + " " + i + fileExt);
    }
}

ومن الواضح أن هذا هو عرضة للسباق الشروط كما ورد في إجابات أخرى.

ليست جميلة، ولكن لدي هذا لفترة من الوقت:

private string getNextFileName(string fileName)
{
    string extension = Path.GetExtension(fileName);

    int i = 0;
    while (File.Exists(fileName))
    {
        if (i == 0)
            fileName = fileName.Replace(extension, "(" + ++i + ")" + extension);
        else
            fileName = fileName.Replace("(" + i + ")" + extension, "(" + ++i + ")" + extension);
    }

    return fileName;
}

بافتراض أن الملفات موجودة بالفعل:

  • ملف.txt
  • ملف (1).txt
  • ملف (2).txt

ستؤدي المكالمة getNextFileName("File.txt") إلى إرجاع "File(3).txt".

ليس الأكثر كفاءة لأنه لا يستخدم البحث الثنائي، ولكن يجب أن يكون مناسبًا لعدد الملفات الصغيرة.ولا يأخذ حالة السباق بعين الاعتبار..

إذا التدقيق في حالة وجود ملف من الصعب جدا يمكنك دائما مجرد إضافة التاريخ والوقت إلى اسم الملف لجعلها فريدة من نوعها:

وFileName.YYYYMMDD.HHMMSS

وربما حتى إضافة ميلي ثانية إذا لزم الأمر.

إذا لم شكل يزعجك ثم يمكنك الاتصال على:

try{
    string tempFile=System.IO.Path.GetTempFileName();
    string file=System.IO.Path.GetFileName(tempFile);
    //use file
    System.IO.File.Delete(tempFile);
}catch(IOException ioe){
  //handle 
}catch(FileIOPermission fp){
  //handle
}

وPS: - الرجاء قراءة المزيد حول هذا الموضوع في MSDN قبل استخدام.

/// <summary>
/// Create a unique filename for the given filename
/// </summary>
/// <param name="filename">A full filename, e.g., C:\temp\myfile.tmp</param>
/// <returns>A filename like C:\temp\myfile633822247336197902.tmp</returns>
public string GetUniqueFilename(string filename)
{
    string basename = Path.Combine(Path.GetDirectoryName(filename),
                                   Path.GetFileNameWithoutExtension(filename));
    string uniquefilename = string.Format("{0}{1}{2}",
                                            basename,
                                            DateTime.Now.Ticks,
                                            Path.GetExtension(filename));
    // Thread.Sleep(1); // To really prevent collisions, but usually not needed
    return uniquefilename;
}

مثل تبلغ دقة DateTime.Ticks 100 نانو ثانية, ، الاصطدامات غير محتملة للغاية.ومع ذلك، فإن Thread.Sleep(1) سيضمن ذلك، لكنني أشك في أن هناك حاجة إليه

وأدخل GUID جديد في اسم الملف.

وتتمثل الفكرة في الحصول على قائمة من الملفات الموجودة، تحليل الخروج الأرقام، ثم جعل المقبل أعلى واحد.

ملحوظة: هذا هو عرضة للسباق الظروف، لذلك إذا كان لديك أكثر من موضوع واحد إنشاء هذه الملفات، <م> نكون حذرين

.

ملحوظة 2: هذا لم تختبر

public static FileInfo GetNextUniqueFile(string path)
{
    //if the given file doesn't exist, we're done
    if(!File.Exists(path))
        return new FileInfo(path);

    //split the path into parts
    string dirName = Path.GetDirectoryName(path);
    string fileName = Path.GetFileNameWithoutExtension(path);
    string fileExt = Path.GetExtension(path);

    //get the directory
    DirectoryInfo dir = new DirectoryInfo(dir);

    //get the list of existing files for this name and extension
    var existingFiles = dir.GetFiles(Path.ChangeExtension(fileName + " *", fileExt);

    //get the number strings from the existing files
    var NumberStrings = from file in existingFiles
                        select Path.GetFileNameWithoutExtension(file.Name)
                            .Remove(0, fileName.Length /*we remove the space too*/);

    //find the highest existing number
    int highestNumber = 0;

    foreach(var numberString in NumberStrings)
    {
        int tempNum;
        if(Int32.TryParse(numberString, out tempnum) && tempNum > highestNumber)
            highestNumber = tempNum;
    }

    //make the new FileInfo object
    string newFileName = fileName + " " + (highestNumber + 1).ToString();
    newFileName = Path.ChangeExtension(fileName, fileExt);

    return new FileInfo(Path.Combine(dirName, newFileName));
}

وبدلا من بدس القرص عدة مرات لمعرفة ما إذا كان لديه البديل معين من اسم الملف المطلوب، يمكن أن تسأل عن قائمة الملفات الموجودة بالفعل والعثور على الفجوة الأولى وفقا لخوارزمية الخاص بك.

public static class FileInfoExtensions
{
    public static FileInfo MakeUnique(this FileInfo fileInfo)
    {
        if (fileInfo == null)
        {
            throw new ArgumentNullException("fileInfo");
        }

        string newfileName = new FileUtilities().GetNextFileName(fileInfo.FullName);
        return new FileInfo(newfileName);
    }
}

public class FileUtilities
{
    public string GetNextFileName(string fullFileName)
    {
        if (fullFileName == null)
        {
            throw new ArgumentNullException("fullFileName");
        }

        if (!File.Exists(fullFileName))
        {
            return fullFileName;
        }
        string baseFileName = Path.GetFileNameWithoutExtension(fullFileName);
        string ext = Path.GetExtension(fullFileName);

        string filePath = Path.GetDirectoryName(fullFileName);
        var numbersUsed = Directory.GetFiles(filePath, baseFileName + "*" + ext)
            .Select(x => Path.GetFileNameWithoutExtension(x).Substring(baseFileName.Length))
            .Select(x =>
                    {
                        int result;
                        return Int32.TryParse(x, out result) ? result : 0;
                    })
            .Distinct()
            .OrderBy(x => x)
            .ToList();

        var firstGap = numbersUsed
            .Select((x, i) => new { Index = i, Item = x })
            .FirstOrDefault(x => x.Index != x.Item);
        int numberToUse = firstGap != null ? firstGap.Item : numbersUsed.Count;
        return Path.Combine(filePath, baseFileName) + numberToUse + ext;
    }
}    

وهنا واحد أن يفصل في مسألة تسمية مرقمة من الاختيار من الملفات:

/// <summary>
/// Finds the next unused unique (numbered) filename.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <param name="inUse">Function that will determine if the name is already in use</param>
/// <returns>The original filename if it wasn't already used, or the filename with " (n)"
/// added to the name if the original filename is already in use.</returns>
private static string NextUniqueFilename(string fileName, Func<string, bool> inUse)
{
    if (!inUse(fileName))
    {
        // this filename has not been seen before, return it unmodified
        return fileName;
    }
    // this filename is already in use, add " (n)" to the end
    var name = Path.GetFileNameWithoutExtension(fileName);
    var extension = Path.GetExtension(fileName);
    if (name == null)
    {
        throw new Exception("File name without extension returned null.");
    }
    const int max = 9999;
    for (var i = 1; i < max; i++)
    {
        var nextUniqueFilename = string.Format("{0} ({1}){2}", name, i, extension);
        if (!inUse(nextUniqueFilename))
        {
            return nextUniqueFilename;
        }
    }
    throw new Exception(string.Format("Too many files by this name. Limit: {0}", max));
}

وهنا هو كيف يمكن أن نسميها إذا كنت تستخدم نظام الملفات

var safeName = NextUniqueFilename(filename, f => File.Exists(Path.Combine(folder, f)));

وهذا هو مجرد عملية السلسلة؛ العثور على الموقع في السلسلة اسم الملف الذي تريد إدراج رقم، وإعادة بناء سلسلة جديدة مع عدد المدرجة. لجعلها إعادة استخدامها، قد ترغب في ابحث عن رقم في ذلك الموقع، وتحليل ذلك إلى عدد صحيح، حتى تتمكن من زيادة عليه.

يرجى ملاحظة أن هذا بشكل عام هذه الطريقة في توليد اسم فريد غير آمنة. هناك سباق حالة .

وربما تكون هناك الجاهزة الحلول لذلك في النظام الأساسي، وأنا لا تصل إلى سرعة مع C # لذلك لا يسعني هناك.

ألق نظرة على الأساليب الموجودة في طريق الطبقة، على وجه التحديد Path.GetFileNameWithoutExtension(), ، و المسار.GetExtension().

قد تجد حتى Path.GetRandomFileName() مفيد!

يحرر:

في الماضي، استخدمت أسلوب محاولة كتابة الملف (بالاسم المطلوب)، ثم استخدام الوظائف المذكورة أعلاه لإنشاء اسم جديد إذا كان ذلك مناسبًا IOException يتم طرحها وتكرارها حتى تنجح.

وهذه الطريقة سوف يضيف مؤشر إلى ملف موجود إذا لزم الأمر:

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

static public string AddIndexToFileNameIfNeeded(string sFileNameWithPath)
{
    string sFileNameWithIndex = sFileNameWithPath;

    while (File.Exists(sFileNameWithIndex)) // run in while scoop so if after adding an index the the file name the new file name exist, run again until find a unused file name
    { // File exist, need to add index

        string sFilePath = Path.GetDirectoryName(sFileNameWithIndex);
        string sFileName = Path.GetFileNameWithoutExtension(sFileNameWithIndex);
        string sFileExtension = Path.GetExtension(sFileNameWithIndex);

        if (sFileName.Contains('_'))
        { // Need to increase the existing index by one or add first index

            int iIndexOfUnderscore = sFileName.LastIndexOf('_');
            string sContentAfterUnderscore = sFileName.Substring(iIndexOfUnderscore + 1);

            // check if content after last underscore is a number, if so increase index by one, if not add the number _01
            int iCurrentIndex;
            bool bIsContentAfterLastUnderscoreIsNumber = int.TryParse(sContentAfterUnderscore, out iCurrentIndex);
            if (bIsContentAfterLastUnderscoreIsNumber)
            {
                iCurrentIndex++;
                string sContentBeforUnderscore = sFileName.Substring(0, iIndexOfUnderscore);

                sFileName = sContentBeforUnderscore + "_" + iCurrentIndex.ToString("000");
                sFileNameWithIndex = sFilePath + "\\" + sFileName + sFileExtension;
            }
            else
            {
                sFileNameWithIndex = sFilePath + "\\" + sFileName + "_001" + sFileExtension;
            }
        }
        else
        { // No underscore in file name. Simple add first index
            sFileNameWithIndex = sFilePath + "\\" + sFileName + "_001" + sFileExtension;
        }
    }

    return sFileNameWithIndex;
}
    private async Task<CloudBlockBlob> CreateBlockBlob(CloudBlobContainer container,  string blobNameToCreate)
    {
        var blockBlob = container.GetBlockBlobReference(blobNameToCreate);

        var i = 1;
        while (await blockBlob.ExistsAsync())
        {
            var newBlobNameToCreate = CreateRandomFileName(blobNameToCreate,i.ToString());
            blockBlob = container.GetBlockBlobReference(newBlobNameToCreate);
            i++;
        }

        return blockBlob;
    }



    private string CreateRandomFileName(string fileNameWithExtension, string prefix=null)
    {

        int fileExtPos = fileNameWithExtension.LastIndexOf(".", StringComparison.Ordinal);

        if (fileExtPos >= 0)
        {
            var ext = fileNameWithExtension.Substring(fileExtPos, fileNameWithExtension.Length - fileExtPos);
            var fileName = fileNameWithExtension.Substring(0, fileExtPos);

            return String.Format("{0}_{1}{2}", fileName, String.IsNullOrWhiteSpace(prefix) ? new Random().Next(int.MinValue, int.MaxValue).ToString():prefix,ext);
        }

        //This means there is no Extension for the file and its fine attaching random number at the end.
        return String.Format("{0}_{1}", fileNameWithExtension, new Random().Next(int.MinValue, int.MaxValue));
    }

وأنا استخدم هذا الرمز إلى إنشاء التوالي _1، _2، _3 الخ .. اسم الملف في كل مرة وجود ملف في تخزين سائل.

وهذا الأمل وظيفة بالتكرار الذاتي يمكن أن يساعد. أنه يعمل بشكل جيد بالنسبة لي.

public string getUniqueFileName(int i, string filepath, string filename)
    {
        string path = Path.Combine(filepath, filename);
        if (System.IO.File.Exists(path))
        {
            string name = Path.GetFileNameWithoutExtension(filename);
            string ext = Path.GetExtension(filename);
            i++;
            filename = getUniqueFileName(i, filepath, name + "_" + i + ext);
        }
        return filename; 
    }

وفعلت مثل هذا:

for (int i = 0; i <= 500; i++) //I suppose the number of files will not pass 500
        {       //Checks if C:\log\log+TheNumberOfTheFile+.txt exists...
            if (System.IO.File.Exists(@"C:\log\log"+conta_logs+".txt"))
            {
                conta_logs++;//If exists, then increment the counter
            }
            else
            {              //If not, then the file is created
                var file = System.IO.File.Create(@"C:\log\log" + conta_logs + ".txt");
                break; //When the file is created we LEAVE the *for* loop
            }
        }

وأعتقد أن هذا الإصدار هو ليس من الصعب جدا مثل الآخرين، وإنها إجابة واضحة عن ما يريده المستخدم.

إذا كنت بحاجة فقط اسم ملف فريد، لذلك، ماذا عن هذا؟

Path.GetRandomFileName()
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top