it-swarm.com.de

Wie würden Sie einen eindeutigen Dateinamen durch Hinzufügen einer Nummer erstellen?

Ich möchte eine Methode erstellen, die entweder einen Dateinamen als string oder FileInfo verwendet und dem Dateinamen eine inkrementierte Zahl hinzufügt, falls die Datei vorhanden ist. Aber ich kann meinen Kopf nicht wirklich darum herumwickeln, wie man das auf eine gute Art und Weise macht.

Zum Beispiel, wenn ich diese FileInfo habe

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

Ich möchte, dass mir die Methode eine neue FileInfo mit C:\file 1.ext if C:\file.ext Gibt und C:\file 2.ext if C:\file 1.ext existiert und so weiter. Etwas wie das:

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.
}
40
Svish

Viele gute Ratschläge hier. Am Ende habe ich eine Methode verwendet, die von Marc in einer Antwort auf eine andere Frage geschrieben wurde. Ein wenig umformatiert und eine weitere Methode hinzugefügt, um die Verwendung von "außen" ein wenig zu erleichtern. Hier ist das Ergebnis:

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

Nur teilweise getestet, wird aber aktualisiert, wenn ich Fehler finde. ( Marc s Code funktioniert gut!) Wenn Sie Probleme damit finden, bitte kommentieren oder bearbeiten oder so etwas :)

25
Svish
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);
    }
}

Dies ist offensichtlich anfällig für Rassenbedingungen, wie in anderen Antworten erwähnt.

47
Mehrdad Afshari

Nicht hübsch, aber ich hatte das schon eine Weile:

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

Angenommen, die Dateien existieren bereits:

  • Datei.txt
  • Datei (1) .txt
  • Datei (2) .txt

der Aufruf getNextFileName ("File.txt") gibt "File (3) .txt" zurück.

Nicht besonders effizient, da keine binäre Suche verwendet wird. Für kleine Dateianzahl sollte dies jedoch in Ordnung sein. Und es berücksichtigt nicht die Rennbedingungen ...

15

Wenn die Überprüfung, ob die Datei vorhanden ist, zu schwer ist, können Sie dem Dateinamen immer ein Datum und eine Uhrzeit hinzufügen, um sie eindeutig zu machen:

Dateiname.YYYYMMDD.HHMMSS

Fügen Sie ggf. sogar Millisekunden hinzu.

11
mga911

Wenn das Format Sie nicht stört, können Sie anrufen:

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: - Bitte lesen Sie vor der Verwendung mehr unter msdn .

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

Da DateTime.Ticks eine Auflösung von 100 Nanosekunden hat , sind Kollisionen äußerst unwahrscheinlich. Ein Thread.Sleep (1) wird dies jedoch sicherstellen, aber ich bezweifle, dass dies erforderlich ist

4
Michael Stum

Fügen Sie eine neue GUID in den Dateinamen ein.

3

Anstatt die Platte mehrmals zu stecken, um herauszufinden, ob sie eine bestimmte Variante des gewünschten Dateinamens hat, können Sie nach der Liste der bereits vorhandenen Dateien fragen und die erste Lücke gemäß Ihrem Algorithmus finden.

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

Die Idee ist, eine Liste der vorhandenen Dateien abzurufen, die Zahlen zu analysieren und die nächsthöhere zu erstellen.

Hinweis: Dies ist anfällig für Race-Bedingungen. Wenn Sie also mehr als einen Thread haben, der diese Dateien erstellt, sollten Sie seien Sie vorsichtig .

Anmerkung 2: Dies ist nicht getestet.

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));
}
1
lc.

Hier ist eine, die die nummerierte Namensfrage von der Prüfung des Dateisystems entkoppelt:

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

Und so nennen Sie es, wenn Sie das Dateisystem verwenden

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

Diese Methode fügt bei Bedarf einen Index zur vorhandenen Datei hinzu:

Wenn die Datei vorhanden ist, ermitteln Sie die Position des letzten Unterstrichs. Wenn der Inhalt nach dem Unterstrich eine Zahl ist, erhöhen Sie diese Zahl. ansonsten ersten Index hinzufügen. Wiederholen Sie den Vorgang, bis der nicht verwendete Dateiname gefunden wurde.

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;
}
0
Gil Epshtain
    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));
    }

Ich verwende diesen Code, um einen fortlaufenden Dateinamen _1, _2, _3 usw. zu erstellen, wenn eine Datei im Blob-Speicher vorhanden ist.

0

Hoffe, diese selbst iterierende Funktion kann helfen. Es funktioniert gut für mich.

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

Ich habe es so gemacht:

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

Ich denke, dass diese Version nicht so hart ist wie die anderen, und es ist eine einfache Antwort auf das, was der Benutzer wollte.

0
Hélder Pinto

Wenn Sie nur einen eindeutigen Dateinamen benötigen, wie wäre es damit?

Path.GetRandomFileName()
0
Oleg

Dies ist nur eine Zeichenfolgeoperation. Suchen Sie in der Dateinamenzeichenfolge den Ort, an dem Sie die Nummer einfügen möchten, und erstellen Sie eine neue Zeichenfolge mit der eingefügten Nummer. Um es wiederverwendbar zu machen, möchten Sie vielleicht suchen eine Nummer an diesem Ort und in eine Ganzzahl parsen, damit Sie sie erhöhen können.

Bitte beachten Sie, dass diese Art der Generierung eines eindeutigen Dateinamens generell unsicher ist. Es gibt offensichtliche Rennbedingungen Gefahren.

Möglicherweise gibt es dafür fertige Lösungen auf der Plattform. Ich bin nicht mit C # auf dem Laufenden, daher kann ich dort nicht helfen.

0
unwind

Sehen Sie sich die Methoden in der Path -Klasse an, insbesondere Path.GetFileNameWithoutExtension () und Path.GetExtension () .

Sie können sogar Path.GetRandomFileName () nützlich finden!

Bearbeiten:

In der Vergangenheit habe ich versucht, die Datei (mit meinem gewünschten Namen) zu schreiben, und dann mit den oben genannten Funktionen einen neuen Namen zu erstellen, wenn eine entsprechende IOException ausgelöst wird, bis der Vorgang erfolgreich ist.

0
Steve Guidi