2013-08-01 18 views
11

我正在創建一個程序,它將創建一個文件並將其保存到文件名爲sample.xml的目錄中。一旦保存文件,當我嘗試再次運行該程序時,它會將舊文件覆蓋到新文件中,因爲它們具有相同的文件名。如何增加文件名,以便每當我嘗試再次運行代碼時,它都會增加文件名。並不會覆蓋現有的。我想首先檢查文件名上的目錄,如果它們是相同的代碼會產生一個新的文件名:如何在Python中創建遞增文件名?

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

回答

0

兩種方式做到這一點是:

  1. 檢查是否存在舊文件和如果它存在嘗試下一個文件名+1
  2. 保存狀態數據的地方

一種簡單的方法來做到這一點蝙蝠是:

import os.path as pth 
filename = "myfile" 
filenum = 1 
while (pth.exists(pth.abspath(filename+str(filenum)+".py")): 
    filenum+=1 
my_next_file = open(filename+str(filenum)+".py",'w') 

作爲設計的東西,while True會減慢速度而不是代碼的可讀性一個偉大的事情


編輯:@EOL來稿/想法

所以我覺得沒有.format乍看起來更具可讀性 - 但使用.format是通用性和約定,以便更好。

import os.path as pth 
filename = "myfile" 
filenum = 1 
while (pth.exists(pth.abspath(filename+str(filenum)+".py")): 
    filenum+=1 
my_next_file = open("{}{}.py".format(filename, filenum),'w') 
# or 
my_next_file = open(filename + "{}.py".format(filenum),'w') 

,你不必ABSPATH使用 - 如果你願意,你可以使用相對路徑,我更喜歡ABS路徑有時是因爲它有助於恢復正常的路徑傳遞:)。

import os.path as pth 
filename = "myfile" 
filenum = 1 
while (pth.exists(filename+str(filenum)+".py"): 
    filenum+=1 
##removed for conciseness 
+0

這裏'format()'方法比字符串連接更清晰。我認爲while循環很好,在這裏。在另一個話題上,爲什麼使用'abspath()'? – EOL

+0

格式更清晰,但他必須查看字符串格式;乍看之下,這很容易理解。和abspath,因爲我忽略符號鏈接:/ ....可能導致混淆錯誤 –

+0

雖然我明白你的觀點,但我相信即使是初學者也應該顯示Pythonic的例子,以便他們養成良好的習慣。 'format()'的行爲真的很容易理解,甚至猜測:'「{} {} .py」.format(filename,filenum)'。它比這裏介紹的算法更簡單。 :) – EOL

27

我將通過sample[int].xml迭代例如,抓住不使用一個文件或目錄下一個可用的名稱。

import os 

i = 0 
while os.path.exists("sample%s.xml" % i): 
    i += 1 

fh = open("sample%s.xml" % i, "w") 
.... 

這應該給你sample0.xml開始,然後sample1.xml

注意,默認情況相對文件符號涉及到的文件目錄/文件夾中運行代碼從。必要時使用絕對路徑。使用os.getcwd()讀你當前目錄os.chdir(path_to_dir)設置新的當前目錄

+1

請問在這裏什麼是無用或無建設性的?沒有留下(建設性)評論的投票似乎對我更沒有建設性。 – bossi

+0

'isfile()'不正確:目錄將匹配。你想要'exists()',而這是@Eiyrioüvon Kauyf的答案。此外,相對路徑並不完全「相對於運行代碼的目錄」。它們通常相對於「當前目錄」(默認情況下是代碼運行的目錄)。例如,當前目錄可以在程序中更改。 – EOL

+0

os.path.isfile()與目錄匹配的事實對我來說是新事物(並且不像你在Python 3.3/win上爲我描述的那樣),這不就是爲什麼os.path.isdir()在地方來區分兩者? 關於我在帖子中對相對路徑符號的評論,既沒有Oliver Ven Quilnet也沒有我的例子明確地改變_current directory_,我想我簡單地指出了它對於給定的context_。 – bossi

4

嘗試設置計數變量,然後遞增嵌套在您寫入文件的同一個循環內的變量。將計數循環包含在具有轉義字符的文件名中,因此每個循環都會打勾+1,所以文件中的數字。

從我完成了一個項目的某些代碼:

numberLoops = #some limit determined by the user 
currentLoop = 1 
while currentLoop < numberLoops: 
    currentLoop = currentLoop + 1 

    fileName = ("log%d_%d.txt" % (currentLoop, str(now()))) 

參考:

from time import mktime, gmtime 

def now(): 
    return mktime(gmtime()) 

這可能是你的情況不相關,但我運行此程序的多個實例,使噸文件。希望這可以幫助!

+2

Python對此有for循環,它們比模擬它們的while循環更快地閱讀和理解。此外,'%'操作符已被棄用。儘管如此,它並沒有失望,因爲它完成了這項工作 - 它並不是以首選的Python方式實現的。 – EOL

+0

格式字符串存在問題:您使用'%d'格式化字符串,並引發異常。 – EOL

+0

感謝您的支持。它應該是一個%s,我匆忙地重新輸入這個,而不是從我的源代碼複製。謝謝! – ford

1

沒有存儲在一個額外的文件狀態數據,更快的解決方案,這裏介紹的那些將做到以下幾點:

from glob import glob 
import os 

files = glob("somedir/sample*.xml") 
files = files.sorted() 
cur_num = int(os.path.basename(files[-1])[6:-4]) 
cur_num += 1 
fh = open("somedir/sample%s.xml" % cur_num, 'w') 
rs = [blockresult] 
fh.writelines(rs) 
fh.close() 

這也將不斷增加,即使某些低版本的文件消失。

這裏的其他解決方案,我想(通過Eiyrioü指出)是保持包含您最近數的臨時文件的想法:

temp_fh = open('somedir/curr_num.txt', 'r') 
curr_num = int(temp_fh.readline().strip()) 
curr_num += 1 
fh = open("somedir/sample%s.xml" % cur_num, 'w') 
rs = [blockresult] 
fh.writelines(rs) 
fh.close() 
使用
+0

您的'cur_num'計算僅適用於1位數字,它不夠一般。 – EOL

+0

好點,更新。 – Vorticity

1

又如遞歸

import os 
def checkFilePath(testString, extension, currentCount): 
    if os.path.exists(testString + str(currentCount) +extension): 
     return checkFilePath(testString, extension, currentCount+1) 
    else: 
     return testString + str(currentCount) +extension 

用途:

checkFilePath("myfile", ".txt" , 0) 
4
def get_nonexistant_path(fname_path): 
    """ 
    Get the path to a filename which does not exist by incrementing path. 

    Examples 
    -------- 
    >>> get_nonexistant_path('/etc/issue') 
    '/etc/issue-1' 
    >>> get_nonexistant_path('whatever/1337bla.py') 
    'whatever/1337bla.py' 
    """ 
    if not os.path.exists(fname_path): 
     return fname_path 
    filename, file_extension = os.path.splitext(fname_path) 
    i = 1 
    new_fname = "{}-{}{}".format(filename, i, file_extension) 
    while os.path.exists(new_fname): 
     i += 1 
     new_fname = "{}-{}{}".format(filename, i, file_extension) 
    return new_fname 

你打開文件之前,調用

fname = get_nonexistant_path("sample.xml") 

這要麼給你'sample.xml'或 - 如果此alreay存在 - 'sample-i.xml'其中i爲最低正整數,該文件不存在。

我推薦使用os.path.abspath("sample.xml")。如果您有~作爲主目錄,您可能首先需要expand it

請注意,如果您有多個實例同時運行,那麼使用此簡單代碼可能會出現競態條件。如果這可能是一個問題,請檢查this question

0

按順序檢查每個文件名以查找下一個可用的文件名,可以使用少量文件正常工作,但隨着文件數量的增加,文件名會迅速變慢。

下面是日誌(n)時間內找到下一個可用的文件名的版本:

import os 

def next_path(path_pattern): 
    """ 
    Finds the next free path in an sequentially named list of files 

    e.g. path_pattern = 'file-%s.txt': 

    file-1.txt 
    file-2.txt 
    file-3.txt 

    Runs in log(n) time where n is the number of existing files in sequence 
    """ 
    i = 1 

    # First do an exponential search 
    while os.path.exists(path_pattern % i): 
     i = i * 2 

    # Result lies somewhere in the interval (i/2..i] 
    # We call this interval (a..b] and narrow it down until a + 1 = b 
    a, b = (i/2, i) 
    while a + 1 < b: 
     c = (a + b)/2 # interval midpoint 
     a, b = (c, b) if os.path.exists(path_pattern % c) else (a, c) 

    return path_pattern % b 

爲了測量速度提高我寫了創建10,000個文件一個小的測試功能:

for i in range(1,10000): 
    with open(next_path('file-%s.foo'), 'w'): 
     pass 

並實現了原始的方法:

def next_path_naive(path_pattern): 
    """ 
    Naive (slow) version of next_path 
    """ 
    i = 1 
    while os.path.exists(path_pattern % i): 
     i += 1 
    return path_pattern % i 

而且這裏的結果:

快速版本:

real 0m2.132s 
user 0m0.773s 
sys 0m1.312s 

天真的版本:

real 2m36.480s 
user 1m12.671s 
sys 1m22.425s 

最後,請注意,這兩種方法是容易受到競爭情況,如果多個演員都試圖在同一時間創建序列中的文件。