Python复制文件到新目录并重命名,如果文件名已存在

73

我已经阅读了这篇文章,但是当我把它应用到我的代码中时,它只能运行几次。

我正在使用Python遍历一个目录(假设称为"移动目录"),将主要匹配唯一ID的PDF文件复制到另一个目录(基本目录)的相应文件夹(具有相应的唯一ID)。我最初使用shutil.copy进行复制,但是如果存在重复文件,它会覆盖现有文件。

我想能够搜索相应的文件夹以查看文件是否已经存在,并在出现多个文件时迭代地对其命名。

例如:

  • 将文件1234.pdf复制到基本目录中的文件夹1234中。
  • 如果1234.pdf已经存在,则将其命名为1234_1.pdf,
  • 如果另一个PDF被复制为1234.pdf,则它将被命名为1234_2.pdf。

以下是我的代码:

import arcpy
import os
import re
import sys
import traceback
import collections
import shutil

movdir = r"C:\Scans"
basedir = r"C:\Links"

try:
    #Walk through all files in the directory that contains the files to copy
    for root, dirs, files in os.walk(movdir):
        for filename in files:
            #find the name location and name of files
            path = os.path.join(root, filename)
            print path
            #file name and extension
            ARN, extension = os.path.splitext(filename)
            print ARN

            #Location of the corresponding folder in the new directory
            link = os.path.join(basedir,ARN)

            # if the folder already exists in new directory
            if os.path.exists(link):

                #this is the file location in the new directory
                file = os.path.join(basedir, ARN, ARN)
                linkfn = os.path.join(basedir, ARN, filename)

                if os.path.exists(linkfn):
                    i = 0
                    #if this file already exists in the folder
                    print "Path exists already"
                    while os.path.exists(file + "_" + str(i) + extension):
                        i+=1
                    print "Already 2x exists..."
                    print "Renaming"
                    shutil.copy(path, file + "_" + str(i) + extension)
                else:

                    shutil.copy(path, link)
                    print ARN + " " +  "Copied"
            else:
                print ARN + " " + "Not Found"

1
不,结构是不同的。例如,movdir是财产信息的扫描,并按街道名称排列,pdf文件以唯一ID命名。因此,C:\ Scans \ Main St \ 1234.pdf basedir是一个新的结构,将根据其唯一ID安排特定财产的所有信息。所以C:\ Links \ 1234,未来可能会有其他子文件夹,但现在我只希望将其复制到C:\ Links \ 1234 \ 1234.pdf。 - GISHuman
1
检查filename_fix_existing(filename) - Grijesh Chauhan
5个回答

45
有时候重新开始会更容易...如果有任何拼写错误,我很抱歉,因为我还没有时间进行彻底的测试。
movdir = r"C:\Scans"
basedir = r"C:\Links"
# Walk through all files in the directory that contains the files to copy
for root, dirs, files in os.walk(movdir):
    for filename in files:
        # I use absolute path, case you want to move several dirs.
        old_name = os.path.join( os.path.abspath(root), filename )

        # Separate base from extension
        base, extension = os.path.splitext(filename)

        # Initial new name
        new_name = os.path.join(basedir, base, filename)

        # If folder basedir/base does not exist... You don't want to create it?
        if not os.path.exists(os.path.join(basedir, base)):
            print os.path.join(basedir,base), "not found" 
            continue    # Next filename
        elif not os.path.exists(new_name):  # folder exists, file does not
            shutil.copy(old_name, new_name)
        else:  # folder exists, file exists as well
            ii = 1
            while True:
                new_name = os.path.join(basedir,base, base + "_" + str(ii) + extension)
                if not os.path.exists(new_name):
                   shutil.copy(old_name, new_name)
                   print "Copied", old_name, "as", new_name
                   break 
                ii += 1

1
谢谢您的回复,但是当我运行代码时出现了一个错误,提示“ii”未定义。可能是因为我正在使用2.7版本(它与ArcGIS兼容,而后者可能会在以后与代码集成)。 - GISHuman
3
不,是我搞错了。应该是ii = 1(而不是0,就像我们在另一个答案中说的那样),索引应该是0。 - Jblasco
在 while 循环内,应该是“if not os.path.exists(new_name)”,对吗?我的意思是,如果文件不存在,那么我们应该用索引“ii”创建它。 - Lucaribou
如果您想要保留元数据,请考虑使用shutil.copy2。https://docs.python.org/3/library/shutil.html - JStrahl

44
我总是使用时间戳,因此文件已经存在是不可能的:
import os
import shutil
import datetime

now = str(datetime.datetime.now())[:19]
now = now.replace(":","_")

src_dir="C:\\Users\\Asus\\Desktop\\Versand Verwaltung\\Versand.xlsx"
dst_dir="C:\\Users\\Asus\\Desktop\\Versand Verwaltung\\Versand_"+str(now)+".xlsx"
shutil.copy(src_dir,dst_dir)

7
除非同时运行代码两次,否则文件不存在。 - bers
1
虽然这是一个不错的解决方案,但它并没有回答我的问题,因为有重复的文件名,这些文件名包含了不同的信息,所以需要采用迭代命名方案...文件的日期是无关紧要的。 - GISHuman
我喜欢这个解决方案;如何修改它以仅保留最新的备份并删除旧的备份? - FMFF

38

对我来说shutil.copy是最好的:

import shutil

#make a copy of the invoice to work with
src="invoice.pdf"
dst="copied_invoice.pdf"
shutil.copy(src,dst)
您可以根据需要更改文件的路径。

7
这个回答没有解决主题帖子提出的问题,即如何处理已经存在的文件。您能否详细说明如何检测现有的文件并重命名它们?请提供更完整的答案。 - Alejandro Piad
1
@AlejandroPiad,虽然它并没有直接回答我的问题,但确实对我有所帮助。这可能不是 OP 问题的直接答案,但它确实简化了很多。这样做有一个优点!任何人甚至 OP 都可以理解这个答案,并将其作为解决他/她问题的指南。 - Ice Bear
1
@AlejandroPiad,现在我又回来看这个答案,它再次解决了我的问题。谢谢Alex。 - Ice Bear

6
我认为您遇到了缩进问题,至少在您在这里编写的代码中是如此:
while not os.path.exists(file + "_" + str(i) + extension):
   i+=1
   print "Already 2x exists..."
   print "Renaming"
   shutil.copy(path, file + "_" + str(i) + extension)

should be:

while os.path.exists(file + "_" + str(i) + extension):
    i+=1
print "Already 2x exists..."
print "Renaming"
shutil.copy(path, file + "_" + str(i) + extension)

请检查一下,谢谢!

1
很遗憾,它没有改变任何东西。 - GISHuman
1
如果您能更新一下代码,包括您所做的更改,即使它们没有起作用,那就太好了。 - Jblasco
1
我认为我的更正中不应该有“不”,对此感到抱歉!我会立即进行编辑。 - Jblasco
1
我去掉了“不”,现在它可以工作了!但是重复的文件名为1234_0,我想将其命名为1234_1。我认为这与我放置i+=1的位置有关。我尝试过移动它,但无济于事! - GISHuman
很高兴它起作用了!如果你从i=0开始,它会尝试先构建它是正常的。尝试使用i=1。 - Jblasco

-1
import os
import shutil
import glob

src = r"C:\Source"
dest = r"C:\Destination"
par = "*"
i=1
d = []
for file in glob.glob(os.path.join(src,par)):
    f = str(file).split('\\')[-1]
    for n in glob.glob(os.path.join(dest,par)):
        d.append(str(n).split('\\')[-1])
    if f not in d:
        print("copied",f," to ",dest)
        shutil.copy(file,dest)
    else:
        f1 = str(f).split(".")
        f1 = f1[0]+"_"+str(i)+"."+f1[1]
        while f1 in d:
            f1 = str(f).split(".")
            f1 = f1[0]+"_"+str(i)+"."+f1[1]
            print("{} already exists in {}".format(f1,dest))
            i =i + 1
        shutil.copy(file,os.path.join(dest,f1))
        print("renamed and copied ",f1 ,"to",dest)
        i = 1

1
请在您的回答中提供更多细节。目前的写法让人难以理解您的解决方案。 - Community
假设我们有两个目录S和D。如果我们想要从S复制文件到D,如果要复制的文件(例如file.ext)已经存在于D中,则将其重命名为file_1.ext并将其复制到D中,同样地,如果file_1.ext存在,则将其更名为file_2.ext。 - DILESH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接