Question

Je voudrais créer une méthode qui prend soit un nom de fichier comme un ou string et ajoute un FileInfo nombre incrémentée au nom du fichier si le fichier existe. Mais ne peut pas tout à fait envelopper la tête autour de la façon de le faire dans le bon sens.

Par exemple, si j'ai FileInfo

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

Je voudrais que la méthode pour me donner une nouvelle FileInfo avec fichier C: \ 1.ext si C: \ fichier.ext existait, et fichier C: \ 2.ext si fichier C: \ 1.ext existait et ainsi de suite. Quelque chose comme ceci:

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.
}
Était-ce utile?

La solution 2

Beaucoup de bons conseils ici. Je fini par utiliser une méthode écrite par Marc une réponse à une autre question. Reformaté un tout petit peu et a ajouté une autre méthode pour le rendre un peu plus facile à utiliser « de l'extérieur ». Voici le résultat:

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

En partie seulement testé jusqu'à présent, mais mettra à jour si je trouve des bugs avec elle. ( Code Marc s fonctionne bien!) Si vous trouvez des problèmes avec elle, s'il vous plaît commentaire ou modifier ou quelque chose :)

Autres conseils

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

Évidemment, ceci est vulnérable à la race des conditions comme indiqué dans d'autres réponses.

Pas assez, mais je l'ai eu pendant un certain temps:

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

En supposant que les fichiers existent déjà:

  • Fichier.txt
  • Fichier (1) txt
  • Fichier (2) txt

le getNextFileName d'appel ( "Fichier.txt") retournera "Fichier (3) txt".

Pas le plus efficace car il n'utilise pas la recherche binaire, mais devrait être ok pour le nombre de petits fichiers. Et il ne prend pas condition de course en compte ...

Si vérifier si le fichier existe est trop dur, vous pouvez toujours ajouter une date et l'heure au nom du fichier pour le rendre unique:

FileName.YYYYMMDD.HHMMSS

Peut-être même ajouter millisecondes si nécessaire.

Si le format ne vous dérange pas alors vous pouvez appeler:

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: - S'il vous plaît en savoir plus sur ce msdn avant d'utiliser.

/// <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 a une résolution de 100 nanosecondes , les collisions sont extrêmement peu probable. Cependant, un Thread.Sleep (1) veillera à ce que, mais je doute qu'il est nécessaire

Insérez un nouveau GUID dans le nom du fichier.

L'idée est d'obtenir une liste des fichiers existants, analyser les chiffres, puis faire le suivant plus élevé.

Note: Ceci est vulnérable aux conditions de race, donc si vous avez plus d'un fil la création de ces fichiers, être prudent

.

Note 2:. Ceci est non testé

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

Au lieu de piquer le disque plusieurs fois pour savoir si elle a une variante particulière du nom de fichier désiré, vous pouvez demander la liste des fichiers qui existent déjà et trouver le premier espace en fonction de votre algorithme.

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

Voici qui découple la question nommant numérotée à partir du contrôle du système de fichiers:

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

Et voici comment vous pouvez l'appeler si vous utilisez le système de fichiers

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

Ceci est juste une opération de chaîne; trouver l'emplacement dans la chaîne de nom de fichier où vous souhaitez insérer le numéro, et re-construire une nouvelle chaîne avec le nombre inséré. Pour le rendre réutilisable, vous voudrez peut-être chercher un numéro à cet endroit, et analyser dehors dans un entier, de sorte que vous pouvez incrémenter.

S'il vous plaît noter que cela en général, cette façon de générer un nom de fichier unique est précaire; il y a des href="http://en.wikipedia.org/wiki/Race_condition" évidentes .

Il pourrait y avoir des solutions toutes prêtes pour cela dans la plate-forme, je ne suis pas à la vitesse avec C #, donc je ne peux pas aider.

Jetez un oeil sur les méthodes de la Chemin classe, en particulier Path.GetFileNameWithoutExtension () et Path.GetExtension () .

Vous pouvez même trouver Path.GetRandomFileName () utile!

Modifier

Dans le passé, je l'ai utilisé la technique de tenter d'écrire le fichier (avec mon nom désiré), puis en utilisant les fonctions ci-dessus pour créer un nouveau nom si un est jeté approprié IOException, répéter jusqu'à ce qu'elle réussisse.

Cette méthode ajoutera un index au fichier existant si nécessaire:

Si le fichier existe, trouver la position du dernier trait de soulignement. Si le contenu après le trait de soulignement est un nombre, augmenter ce nombre. autrement ajouter premier indice. répéter jusqu'à ce que le nom de fichier utilisé trouvés.

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

J'utilise ce code pour créer une consécutif _1, _2, _3 etc .. nom de fichier chaque fois qu'un fichier existe dans le stockage blob.

Hope cette fonction d'auto-itérer peut aider. Cela fonctionne très bien pour moi.

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

Je l'ai fait comme ceci:

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

Je pense que cette version est pas si difficile comme les autres, et il est une réponse simple pour ce que l'utilisateur voulait.

Si vous avez juste besoin d'un nom de fichier unique, donc, que diriez-vous?

Path.GetRandomFileName()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top