2012-12-13 15 views
6

Czy python ma wbudowaną funkcjonalność? Moim pomysłem jest, że działa on w taki sam sposób, jak system operacyjny działa, jeśli plik jest wyprowadzany do katalogu, w którym plik o tej nazwie już istnieje. Np. Jeśli istnieje plik "plik.pdf", utworzy "plik2.pdf", a następnym razem "plik3.pdf".python: Utwórz plik, ale jeśli istnieje, dodaj numer

+0

To będzie na ogół funkcją aplikacji lub programu tworzenia plików więc nie ma, nie ma natywnej funkcjonalności tak . Biorąc pod uwagę katalog i nazwę pliku, możesz sam coś stworzyć. – timc

+1

sprawdź to http://code.activestate.com/recipes/578116-move-files-with-rename-if-required/ – avasal

+0

sprawdź ['filename_fix_existing (nazwa pliku)'] (https://github.com/steveeJ /python-wget/blob/master/wget.py#L72) –

Odpowiedz

7

W pewnym sensie Python ma tę funkcję wbudowaną w moduł tempfile. Niestety, musisz wejść do prywatnej zmiennej globalnej, tempfile._name_sequence. Oznacza to, że oficjalnie, tempfile nie daje gwarancji, że w przyszłych wersjach _name_sequence nawet istnieje - jest to szczegół implementacji. Ale jeśli jesteś w porządku z użyciem tak, to pokazuje, w jaki sposób można tworzyć unikatowe nazwy plików formie file#.pdf w określonym katalogu, takich jak /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

Dziękuję za odpowiedź! Tricky rzeczy, aby dowiedzieć się z dokumentów;) Ja wybieram własne, prostsze podejście, ale ta odpowiedź wyraźnie odpowiada na to, co zastanawiałem – Parham

+0

Tak, to jest prawdopodobnie mądry wybór, jeśli nie potrzebujesz specjalnych możliwości 'tempfile '. Moduł 'tempfile' stara się unikać określonych warunków wyścigu, bezpieczeństwa i ataków typu" odmowa usługi ". Korzystanie z numeracji sekwencyjnej powoduje, że powyższy kod jest podatny na atak typu "odmowa usługi".I nie jestem do końca pewien, czy powyższe jest bezpieczne także przed warunkami wyścigowymi lub innymi zagrożeniami bezpieczeństwa. – unutbu

1

starałem się wdrożyć to samo w moim projekcie ale odpowiedź @ unutbu wydawała zbyt „ciężki” dla moich potrzeb więc wymyśliłem następujący kod wreszcie:

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 

wszelki wypadek ktoś natknął się na to i wymaga czegoś prostszego.

0

Ponieważ hackowanie plików tymczasowych A) jest hackerem i B) nadal wymaga przyzwoitej ilości kodu, poszedłem z ręczną implementacją. Zasadniczo trzeba:

  1. Sposobem Safely create a file if and only if it does not exist (to jest to, co daje nam Hack tempfile).
  2. Generator nazw plików.
  3. Funkcja owijania w celu ukrycia bałaganu.

ja zdefiniował safe_open które mogą być używane tak jak otwarte:

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

Nie testowałem tego jeszcze, ale to powinno działać, iteracji nad możliwych nazw plików do pliku w pytaniu nie istnieje w które wskazują, że się łamie.

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

niedawno natknąłem samo i tutaj jest moje podejście:

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

Działa to dla mnie. Początkowa nazwa pliku jest 0.yml, jeśli istnieje, to doda jeden aż spełnienia wymogu

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 
Powiązane problemy