python实现既定后缀名的文件移动

"""
问题描述:

 输入文件夹路径,设定文件后缀要求,筛选文件移动到待保存文件路径。需保证筛选文件依然保留文件夹的子目录关系。

输入文件夹路径:r"C:\Users\deng\Desktop\kpi";
后缀名筛选:[txt,xlsx,bmp];
保存文件路径:"F:\xxxx\123\sample"
ex:
符合条件的文件:C:\Users\deng\Desktop\kpi\2\3\ni.txt
需要保存到:F:\xxxx\123\sample\kpi\2\3\ni.txt
"""
import os
import shutil
import traceback
def filterfile(file_dir,save_dir,suffix):
    outsidefile=[]
    outsiderfolder=[]
    path=os.listdir(file_dir)
    print(path)
    #['1', '2', 'plan.txt'],只返回文件夹和文件的name
    for i in path:
        if os.path.isfile(file_dir+"\\"+i):
            outsidefile.append(file_dir+"\\"+i)
        elif os.path.isdir(file_dir+"\\"+i):
            outsiderfolder.append(file_dir+"\\"+i)
        print(outsidefile,outsiderfolder)
        #['C:\\Users\\deng\\Desktop\\kpi\\plan.txt'] ['C:\\Users\\deng\\Desktop\\kpi\\1', 'C:\\Users\\deng\\Desktop\\kpi\\2']
    if len(outsidefile)!=0:
        for file in outsidefile:
            file_type = file.split(".")[-1]  # 返回后缀名
            outsidefileheadpath=file.split("\\")[-2]
            if (file_type in suffix):  # 后缀名属于suffix内
                isExists=os.path.exists(save_dir+"\\"+outsidefileheadpath)
                if not isExists:
                    os.makedirs(save_dir+"\\"+outsidefileheadpath)
                    print("文件夹创建成功")
                else:
                    print("文件夹已经创建了")
                shutil.copy(file,save_dir+"\\"+outsidefileheadpath)
    #接下来对文件夹进行第二层的处理,
    for inside in outsiderfolder:
        insiderfile=[]
        insiderfolder=[]
        path1=os.listdir(inside)
        print(path1)
        for j in path1:
            if os.path.isfile(inside+"\\"+j):
                insiderfile.append(inside+"\\"+j)
            elif os.path.isdir(inside+"\\"+j):
                insiderfolder.append(inside+"\\"+j)
        print(insiderfile, insiderfolder)
        if len(insiderfile)!=0:
            for file in insiderfile:
                file_type = file.split(".")[-1]  # 返回后缀名,1\\abc.cpp
                file_headpath=file.split("\\")[-2]
                file_headheadpath=file.split("\\")[-3]
                if (file_type in suffix):  # 后缀名属于suffix内
                    isExists = os.path.exists(save_dir + "\\"+file_headpath)
                    if not isExists:
                        os.makedirs(save_dir + "\\" + file_headpath)
                        print("文件夹创建成功")
                    else:
                        print("文件夹已经创建了")
                    shutil.copy(file, save_dir + "\\" +file_headpath)
        for file in insiderfolder:
            filetype=file.split(".")[-1]
            fileheadpath=file.split("\\")[-2]
            if(filetype in suffix):
                isExists = os.path.exists(save_dir + "\\" + fileheadpath)
                if not isExists:
                    os.makedirs(save_dir + "\\" + fileheadpath)
                    print("文件夹创建成功")
                else:
                    print("文件夹已经创建了")
                shutil.copy(file,save_dir+"\\"+fileheadpath)
if __name__ == "__main__":
     filterfile(r"C:\Users\deng\Desktop\kpi",r"D:\sample",["txt"])

代码demo1,对文件操作的理解在于用列表来进行一层、两层深度的操作,在写代码过程十分冗杂且繁琐,不符合计算机编程思维。

此demo1只适合文件夹只有一两层的子文件目录,且子文件夹同级没有文件,抽象不足。

import os
import shutil
import traceback

def filterfile(file_dir,save_dir, suffix):
    filelist = []  #符合后缀要求的文件
    for dirpath, dirnames, filenames in os.walk(file_dir):#遍历
        for file in filenames:
            file_type = file.split(".")[-1]  # 返回后缀名
            dirnames = ",".join('%s' % id for id in dirnames)
            if (file_type in suffix):  # 后缀名属于suffix内
                file_fullpath = os.path.join(dirpath, dirnames, file)#file的绝对路径
                filelist.append(file_fullpath)


    for file in filelist:
        headpath, filename=os.path.split(file)#headpath为上级路径,filename为文件夹名字
        print(headpath,filename)#F:\first\kpi\1\sample 123.xlsx
        headpath_filename,headfile=os.path.split(headpath)
        isExists = os.path.exists(save_dir + "\\" + headfile)
        print(isExists)
        if not isExists:
            os.makedirs(save_dir + "\\" + headfile)
            print("文件夹创建成功")
        else:
            print("文件夹已经创建了")
        shutil.copy(file, save_dir + "\\" + headfile)

def test():
    try:
        return 1 / 0
    except Exception as e:
    	# 默认在终端打印异常信息, 默认色彩是红色
        traceback.print_exc()
        # 使用变量接收错误信息
        err = traceback.format_exc()
        print(err) # 使用print打印将不具备色彩
        return 0


if __name__ == "__main__":
    print("此脚本对单个文件夹内的N个子文件夹中的文件进行遍历,通过后缀名的筛选把符合条件的文件复制到指定文件夹中")

    print("请输入你的文件夹所在位置,如r'F:\pentakill\kpi'")
    file_dir=input()
    print("请输入筛选文件保存位置:如'E:\个人文件\筛选文件'")
    save_dir=input()
    print('请输入符合文件筛选的后缀名:\n\t需打英文双引号,如"xlsx","txt","bmp"')
    suffix=input()
    filterfile(file_dir,save_dir,suffix)
    input("程序运行完成。")
    print(test())
   

代码demo2,对文件和子目录的关系是靠split函数、join函数来拼接、拆分,考虑的是子目录在列表中的相对位置。但是若子文件夹中既有文件,又有文件夹,将会导致筛选不完全,这是第二次demo写的缺陷,对于文件夹内文件和子目录复杂的情况下依然不能满足。

import shutil
import os
def filecopy(url,save_dir,suffix):
    listfile=[]#符合条件的文件list
    listfilepath=[]#文件夹list
    

    for filepath, dirnames, filenames in os.walk(url):
        for filename in filenames:
            if filename.split(".")[-1] in suffix:#符合后缀
                real_path=os.path.join(filepath,filename)#真实路径,将目录和文件和在一起
                listfile.append(real_path)
        listfilepath.append(filepath)
    #print(listfile)#符合条件的listfile
    #print(listfilepath)#所有的路径
    urllen=len(url)#输入文件夹路径长度
    #print(urllen)#返回url长度
    """
    listfile 是符合条件的文件,格式是绝对路径
    listfilepath 是url条件的所有目录绝对路径
    下一步目的是要将符合条件的文件,复制到指定位置的文件夹中。
    2 把url之前的替换掉就行了。获得了保存路径
    3 将文件copy到保存路径中去,
    """
    for one in listfile:
        i=save_dir+one[urllen:]#保存路径
        one_path=i.split("\\")[:-1]#获取保存路径的目录
        one_path="\\".join(one_path)#获取保存路径的目录
        print(one_path)
        isExist = os.path.exists(one_path)
        if not isExist:
            os.makedirs(one_path)
            print("文件创建成功")
        else :
            print("文件已经存在")
        shutil.copy(one,one_path)

代码demo3,经过大佬的问题讨论,对于文件和子文件夹的相对路径关系,发现只要将文件夹内的文件和文件夹全部遍历,获取符合后缀名的文件list,通过获取输入文件夹路径的长度,即找到长度、位置,然后将符合后缀的文件路径进行替换,拼接上保存路径。(子文件夹list其实都没有用)

于是完成list中绝对路径和保存文件路径的替换,就意味着可以完成保存路径的正确格式,然后创建保存路径,使用shutil库的copy函数copy即可。

缺陷:但没有考虑文件夹中是否会存在同名的子文件夹或文件。

总结:成熟的编程应该是忽略掉足够的细节,并完成抽象。