2012-12-13 10 views
6

Hat Python irgendwelche eingebaute Funktionalität dafür? Meine Idee ist, dass es so funktionieren würde, wie bestimmte Betriebssysteme funktionieren, wenn eine Datei in ein Verzeichnis ausgegeben wird, in dem bereits eine Datei mit diesem Namen existiert. Wenn "file.pdf" existiert, wird "file2.pdf" und das nächste Mal "file3.pdf" erstellt.Python: Erstelle Datei, aber wenn Name existiert, füge Nummer hinzu

+0

Diese im Allgemeinen die Funktion der Anwendung oder ein Programm wäre nicht die Dateien zu erstellen, so gibt es keine native Funktionen wie diese . Angesichts des Verzeichnisses und Dateinamens könnten Sie selbst etwas erstellen. – timc

+1

überprüfen Sie diese http://code.activestate.com/recipes/578116-move-files-with-rename-if-required/ – avasal

+0

überprüfen Sie ['filename_fix_existing (Dateiname)'] (https://github.com/steveeJ /python-wget/blob/master/wget.py#L72) –

Antwort

7

In gewisser Weise hat Python diese Funktionalität in das Modul tempfile integriert. Leider müssen Sie auf eine private globale Variable tippen, tempfile._name_sequence. Dies bedeutet, dass offiziell tempfile keine Garantie gibt, dass in zukünftigen Versionen sogar _name_sequence existiert - es ist ein Implementierungsdetail. Aber wenn man es mit der Verwendung von ohnehin in Ordnung ist, das zeigt, wie Sie eindeutig benannte Dateien des Formulars file#.pdf in einem bestimmten Verzeichnis erstellen können, wie /tmp:

import tempfile 
import itertools as IT 
import os 

def uniquify(path, sep = ''): 
    def name_sequence(): 
     count = IT.count() 
     yield '' 
     while True: 
      yield '{s}{n:d}'.format(s = sep, n = next(count)) 
    orig = tempfile._name_sequence 
    with tempfile._once_lock: 
     tempfile._name_sequence = name_sequence() 
     path = os.path.normpath(path) 
     dirname, basename = os.path.split(path) 
     filename, ext = os.path.splitext(basename) 
     fd, filename = tempfile.mkstemp(dir = dirname, prefix = filename, suffix = ext) 
     tempfile._name_sequence = orig 
    return filename 

print(uniquify('/tmp/file.pdf')) 
+0

Danke für die Antwort! Knifflige Sachen, um aus der Dokumentation herauszufinden;) Ich wähle meinen eigenen, einfacheren Ansatz, aber diese Antwort beantwortet klar, was ich mich fragte – Parham

+0

Ja, das ist wahrscheinlich eine kluge Wahl, wenn Sie die speziellen Fähigkeiten von 'tempfile nicht brauchen '. Das 'tempfile'-Modul bemüht sich, bestimmte Race Conditions, Sicherheits- und Denial-of-Service-Attacken zu vermeiden. Die Verwendung der sequentiellen Nummerierung macht den obigen Code anfällig für einen Denial-of-Service-Angriff.Und ich bin mir nicht ganz sicher, ob das Obige auch vor Rennbedingungen oder anderen Sicherheitsrisiken sicher ist. – unutbu

1

Ich habe versucht, die gleiche Sache in meinem Projekt zu implementieren aber die Antwort von @ unutbu schien zu ‚schwer‘ für meine Bedürfnisse so kam ich schließlich mit folgendem Code auf:

import os 
index = '' 
while True: 
    try: 
     os.makedirs('../hi'+index) 
     break 
    except WindowsError: 
     if index: 
      index = '('+str(int(index[1:-1])+1)+')' # Append 1 to number in brackets 
     else: 
      index = '(1)' 
     pass # Go and try create file again 

Nur falls jemand zufällig auf diesem und erfordert etwas einfacher.

0

Da der Tempdatei Hack A) ein Hack ist und B) trotzdem eine ordentliche Menge Code benötigt, ging ich mit einer manuellen Implementierung. Sie brauchen grundsätzlich:

  1. Ein Weg zu Safely create a file if and only if it does not exist (das ist, was der Tempfile Hack uns bietet).
  2. Ein Generator für Dateinamen.
  3. Eine Umbruchfunktion, um das Chaos zu verbergen.

definiert ich eine safe_open, die genau wie offen verwendet werden können:

def iter_incrementing_file_names(path): 
    """ 
    Iterate incrementing file names. Start with path and add " (n)" before the 
    extension, where n starts at 1 and increases. 

    :param path: Some path 
    :return: An iterator. 
    """ 
    yield path 
    prefix, ext = os.path.splitext(path) 
    for i in itertools.count(start=1, step=1): 
     yield prefix + ' ({0})'.format(i) + ext 


def safe_open(path, mode): 
    """ 
    Open path, but if it already exists, add " (n)" before the extension, 
    where n is the first number found such that the file does not already 
    exist. 

    Returns an open file handle. Make sure to close! 

    :param path: Some file name. 

    :return: Open file handle... be sure to close! 
    """ 
    flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY 

    if 'b' in mode and platform.system() == 'Windows': 
     flags |= os.O_BINARY 

    for filename in iter_incrementing_file_names(path): 
     try: 
      file_handle = os.open(filename, flags) 
     except OSError as e: 
      if e.errno == errno.EEXIST: 
       pass 
      else: 
       raise 
     else: 
      return os.fdopen(file_handle, mode) 

# Example 
with safe_open("some_file.txt", "w") as fh: 
    print("Hello", file=fh) 
0

Ich habe dies noch nicht getestet, aber es sollte funktionieren, über mögliche Dateinamen, bis die betreffende Datei Iterieren bei nicht existiert welchen Punkt es bricht.

def increment_filename(fn): 
    fn, extension = os.path.splitext(path) 

    n = 1 
    yield fn + extension 
    for n in itertools.count(start=1, step=1) 
     yield '%s%d.%s' % (fn, n, extension) 

for filename in increment_filename(original_filename): 
    if not os.isfile(filename): 
     break 
0

vor kurzem traf ich die gleiche Sache und hier ist mein Ansatz:

import os 

file_name = "file_name.txt" 
if os.path.isfile(file_name): 
    expand = 1 
    while True: 
     expand += 1 
     new_file_name = file_name.split(".txt")[0] + str(expand) + ".txt" 
     if os.path.isfile(new_file_name): 
      continue 
     else: 
      file_name = new_file_name 
      break 
0

Dies funktioniert für mich. Die ursprüngliche Dateiname ist 0.yml, wenn es vorhanden ist, wird es ein hinzufügen, bis die Anforderung erfüllen

import os 
import itertools 

def increment_filename(file_name): 
    fid, extension = os.path.splitext(file_name) 

    yield fid + extension 
    for n in itertools.count(start=1, step=1): 
     new_id = int(fid) + n 
     yield "%s%s" % (new_id, extension) 


def get_file_path(): 
    target_file_path = None 
    for file_name in increment_filename("0.yml"): 
     file_path = os.path.join('/tmp', file_name) 
     if not os.path.isfile(file_path): 
      target_file_path = file_path 
      break 
    return target_file_path 
Verwandte Themen