45 votes

Comment créer un nom de fichier s'incrémentant

Je crée un programme qui va créer un fichier et le sauvegarder dans le répertoire avec le nom de fichier sample.xml. Une fois le fichier enregistré, lorsque j'essaie d'exécuter le programme à nouveau, il écrase l'ancien fichier par le nouveau parce qu'ils ont le même nom de fichier. Comment puis-je incrémenter les noms de fichiers pour que chaque fois que je tente d'exécuter le code à nouveau, il va incrémenter le nom de fichier et ne pas écraser l'ancien. Je pense à vérifier d'abord le nom de fichier dans le répertoire et si ils sont identiques, le code générera un nouveau nom de fichier :

fh = open("sample.xml", "w")
rs = [blockresult]
fh.writelines(rs)
fh.close()

0voto

Ranjit Kashid Points 11

Voici un autre exemple. Le code teste si un fichier existe dans le répertoire ou non. S'il existe, il incrémente le dernier index du nom de fichier et le sauvegarde. Le nom de fichier typique est : Trois lettres du mois_date_lastindex.txt c'est-à-dire May10_1.txt

import time
import datetime
import shutil
import os
import os.path

da=datetime.datetime.now()

data_id =1
ts = time.time()
st = datetime.datetime.fromtimestamp(ts).strftime("%b%d")
data_id=str(data_id)
filename = st+'_'+data_id+'.dat'
while (os.path.isfile(str(filename))):
    data_id=int(data_id)
    data_id=data_id+1
    print(data_id)
    filename = st+'_'+str(data_id)+'.dat'
    print(filename)

shutil.copyfile('Autonamingscript1.py',filename)

f = open(filename,'a+')
f.write("\n\n\n")
f.write("Commentaires sur les données: \n")

f.close()

0voto

david binette Points 41

Numérotation de séquence continue à partir du nom de fichier donné avec ou sans le numéro de séquence ajouté.

Le nom de fichier donné sera utilisé s'il n'existe pas, sinon un numéro de séquence est appliqué, et les écarts entre les nombres seront candidats.

Cette version est rapide si le nom de fichier donné n'est pas déjà séquencé ou est le fichier préexistant numéroté séquentiellement le plus élevé.

Par exemple, le nom de fichier fourni peut être

  • sample.xml
  • sample-1.xml
  • sample-23.xml

    import os import re

    def get_incremented_filename(filename): name, ext = os.path.splitext(filename) seq = 0

    continuer depuis le numéro de séquence existant s'il y en a un

    rex = re.search(r"^(.*)-(\d+)$", name)
    if rex:
        name = rex[1]
        seq = int(rex[2])
    
    while os.path.exists(filename):
        seq += 1
        filename = f"{name}-{seq}{ext}"
    return filename

0voto

hackerb9 Points 541

Utilisez numbered_filename('sample-*.xml')

Python n'a pas de routine pour trouver le prochain nom de fichier dans une séquence numérotée, j'ai donc écrit un module simple (voir ci-dessous). L'utilisation est la suivante :

from numbered_filename import numbered_filename

fn = numbered_filename('sample-*.xml')
fh = open(fn, 'w')
rs = [blockresult]
fh.writelines(rs)
fh.close()

La première fois que le code est exécuté, la sortie sera dans sample-000.xml. La prochaine exécution écrira dans sample-001.xml, puis sample-002.xml, et ainsi de suite. Chaque exécution ultérieure incrémente le numéro de séquence de un.

Le code du module

Enregistrez le code suivant dans un fichier appelé numbered_filename.py.

"""Fournit une fonction pour créer des noms de fichiers incrémentés séquentiellement
basés sur un modèle simple dans lequel un astérisque est remplacé par un
nombre. Le système de fichiers est vérifié pour des fichiers existants qui correspondent
au modèle et le numéro de séquence du nom de fichier retourné est toujours un de plus
que le maximum trouvé.
"""

import glob
if __debug__:
    import os

def numbered_filename(template :str ='', width :int =3) -> str:
    """Renvoie le nom de fichier suivant dans une séquence incrémentée en ajoutant un
    à la plus grande numérotation actuelle dans les noms de fichiers existants.

    template :str: une chaîne avec un astérisque dedans représentant où
                   les nombres sont placés. ('foo-*.txt').

       width :int: nombre optionnel minimum de chiffres pour compléter par des zéros
                   la séquence. Par défaut à 3 ('000', '001', '002', ...)

    Exemple d'utilisation :

        from numbered_filename import numbered_filename
        newfile = numbered_filename('foo-*.txt')
        with open(newfile, 'w') as outfile:
            outfile.write("C'est gagné !")

    Étant donné un modèle de nom de fichier avec un astérisque dedans, tel que
    'foo-*.txt', renvoie le même nom de fichier avec l'astérisque remplacé
    par le prochain numéro dans la séquence, tel que 'foo-007.txt'. Si aucun
    fichier antérieur n'existe, la numérotation commence à zéro ('foo-000.txt').

    Le numéro est complété par des zéros à gauche pour contenir au moins
    trois chiffres, sauf si l'argument optionnel 'width' est donné.
    La complétion par des zéros peut être désactivée avec 'width=0'. Par exemple,
    'numbered_filename("hackerb*", width=0)' pourrait renvoyer 'hackerb9'.
    Notez que 'width' est un minimum et plus de chiffres seront utilisés si
    nécessaire. (Par exemple, 'foo-1000.txt').

    Peu importe le paramètre 'width', les noms de fichiers existants ne
    doivent pas avoir de complétion par des zéros pour être reconnus. Par exemple,
    si un répertoire contient le fichier 'foo-6.txt', le prochain nom de fichier sera
    'foo-007.txt'.

    Cette routine renvoie toujours un nombre plus grand après tout
    fichier existant, même s'il existe un nombre plus petit. Par exemple,
    dans un répertoire contenant uniquement 'foo-099.txt', le fichier suivant serait
    'foo-100.txt', malgré 'foo-000' à '-098.txt' étant possibles.

    Circonstances particulières : Si le modèle est une chaîne vide (''),
    alors la sortie sera simplement un numéro de séquence ('007'). Si le modèle ne contient
    pas d'astérisques ('foo'), alors le numéro est ajouté à la fin du nom de fichier ('foo007'). Si plus d'un
    astérisque est utilisé ('*NSYNC*.txt'), alors seulement le dernier astérisque
    est remplacé par un nombre ('*NSYNC007.txt'). Tous les autres astérisques
    sont conservés comme '*' dans le nom de fichier.

    ATTENTION : Bien que le code tente de renvoyer un nom de fichier inutilisé, il
    n'est pas garanti car il y a une condition de concurrence assez évidente. Pour
    l'éviter, les processus écrivant dans le même répertoire simultanément
    ne doivent pas utiliser le même modèle. N'utilisez pas ceci pour créer des fichiers temporaires dans un répertoire où
    un adversaire pourrait avoir un accès en écriture, comme /tmp -- utilisez plutôt 'mkstemp'.
    """

    if not isinstance(template, str):
        raise TypeError("numbered_filename() nécessite une chaîne en tant que modèle, comme foo-*.txt")

    (filename, asterisk, extension) =  template.rpartition('*')
    if not asterisk:
        (filename, extension) = (extension, filename)
        template=f'{filename}*'

    try:
        files = [int(f.lstrip(filename).rstrip(extension))
                 for f in glob.glob(template)
                 if f.lstrip(filename).rstrip(extension).isdigit()]
        num = sorted(files)[-1]
    except (IndexError, ValueError):
        num = -1

    num = num + 1
    spec = f'0>{width}'
    numstr = format(num, spec)

    if __debug__:
        result = filename + numstr + extension
        if os.path.exists(result):
            raise AssertionError(f'Erreur : "{result}" existe déjà. Condition de course ou bug ?')

    return filename + numstr + extension

Avertissement sur les conditions de course

Ce module résout le problème décrit dans la question, cependant, il ne prétend pas être sécurisé. Si votre programme crée des fichiers temporaires dans un répertoire auquel un adversaire a accès en écriture, comme /tmp, vous devriez utiliser mkstemp() au lieu de numbered_filename().

0voto

twil Points 63

J'ai rencontré une tâche similaire.
Voici ce que j'ai imaginé pour créer des noms de fichiers uniques avec un numéro de séquence automatiquement déterminé.

from pathlib import Path
from glob import glob

targetPath = Path('tmp').resolve() / 'targetFile.txt'
if cnt := len(glob(f"{targetPath.parent}/{targetPath.stem}*{targetPath.suffix}")):
    targetPath = Path(targetPath.parent / f"{targetPath.stem}_{cnt}{targetPath.suffix}")

with open(targetPath,"w") as f:
    ...

-1voto

ted Points 2010

Mes 2 cents: une procédure de nommage incrémental toujours croissante, style macOS

  • get_increased_path("./some_new_dir").mkdir() crée ./some_new_dir ; puis
  • get_increased_path("./some_new_dir").mkdir() crée ./some_new_dir (1) ; puis
  • get_increased_path("./some_new_dir").mkdir() crée ./some_new_dir (2) ; etc.

Si ./some_new_dir (2) existe mais pas ./some_new_dir (1), alors get_increased_path("./some_new_dir").mkdir() crée ./some_new_dir (3) de toute façon, de sorte que les indices augmentent toujours et vous savez toujours lequel est le plus récent


from pathlib import Path
import re

def get_increased_path(file_path):
    fp = Path(file_path).resolve()
    f = str(fp)

    vals = []
    for n in fp.parent.glob("{}*".format(fp.name)):
        ms = list(re.finditer(r"^{} \(\d+\)$".format(f), str(n)))
        if ms:
            m = list(re.finditer(r"\(\d+\)$", str(n)))[0].group()
            vals.append(int(m.replace("(", "").replace(")", "")))
    if vals:
        ext = " ({})".format(max(vals) + 1)
    elif fp.exists():
        ext = " (1)"
    else:
        ext = ""

    return fp.parent / (fp.name + ext + fp.suffix)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X