2012-12-13 32 views
6

python是否有任何內置功能?我的想法是,如果一個文件輸出到一個名稱已經存在的文件的目錄中,它將以某種操作系統的工作方式工作。即:如果「file.pdf」存在,它將創建「file2.pdf」,並在下一次「file3.pdf」。python:創建文件,但如果名稱存在添加編號

+0

這通常是應用程序或程序創建的文件,這樣的功能沒有,就這樣沒有原生功能。鑑於目錄和文件名,你可以自己創建一些東西。 – timc

+1

請查看http://code.activestate.com/recipes/578116-move-files-with-rename-if-required/ – avasal

+0

檢查['filename_fix_existing(filename)'](https://github.com/steveeJ /python-wget/blob/master/wget.py#L72) –

回答

7

從某種意義上說,Python在tempfile模塊中內置了此功能。不幸的是,您必須使用私有全局變量tempfile._name_sequence。這意味着,官方tempfile不保證在將來的版本_name_sequence甚至存在 - 它是一個實現細節。 但如果你是好與無論如何使用它,這顯示瞭如何在指定目錄下創建形式file#.pdf的唯一命名的文件,如/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

謝謝你的回答!狡猾的東西從文檔中找出;)我選擇了我自己的,更簡單的方法,但是這個答案很明顯地回答了我想知道的問題 – Parham

+0

是的,如果你不需要'tempfile的特殊功能,這可能是一個明智的選擇'。 'tempfile'模塊需要努力避免某些競爭條件,安全性和拒絕服務攻擊。使用順序編號可使上述代碼容易受到拒絕服務攻擊。而且我也不完全確定上述情況是否可以避免競爭狀況或其他安全風險。 – unutbu

1

我想實現我的項目中同樣的事情但@ unutbu的回答似乎爲我的需求太「重」,所以我想出了最後下面的代碼:

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 

萬一有人偶然發現了這一點,需要更簡單的東西。

0

由於臨時文件破解A)是一個破解和B)無論如何仍然需要大量的代碼,我去了一個手動的實現。你基本上需要:

  1. 一種方式Safely create a file if and only if it does not exist(這是臨時文件破解給我們的東西)。
  2. 文件名的生成器。
  3. 隱藏混亂的包裝功能。

我定義了可用於就像打開safe_open:我沒有測試過這還

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

但它應該工作,遍歷可能的文件名,直到問題的不存在的文件這指出它打破了。

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

最近我遇到了同樣的事情,這裏是我的方法:

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

這對我的作品。 初始文件名是0.yml,如果存在的話,它會添加一個,直到滿足要求

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 
相關問題