鱼C论坛

 找回密码
 立即注册
查看: 2550|回复: 21

使用os.walk对文件夹递归进行处理时,如何排除特定文件夹

[复制链接]
发表于 2018-11-11 15:36:46 | 显示全部楼层 |阅读模式
10鱼币
本帖最后由 久光 于 2018-11-11 22:12 编辑

小甲鱼Python零基础中有一课,统计自己的代码量,因为我使用的pycharm每建个项目都会有一个“Venv”文件夹,里面有很多py文件,所以统计时我需要排除这个名字的文件夹里的所有文件。

最后写出的代码如下(已排除venv文件夹):
  1. import os
  2. import easygui as g

  3. code_list = [".py", ".java", ".asm"]
  4. code_type_dict = {}
  5. line_count = {}


  6. def choiceDir():
  7.     start_path = g.diropenbox(title="请选择起始目录")
  8.     return start_path


  9. def calculateLines(start_path):
  10.     os.chdir(start_path)
  11.     all_files = os.walk(os.getcwd())
  12.     for i in all_files:
  13.         file_type = os.path.splitext(i)[1]
  14.         if file_type in code_list:
  15.             code_type_dict.setdefault(file_type,0)
  16.             code_type_dict[file_type] += 1
  17.             line_count.setdefault(file_type,0)
  18.             for each_line in i:
  19.                 line_count[file_type] += 1
  20.         elif file_type == "" and i != "venv":
  21.             calculateLines(i)
  22.             os.chdir("..")


  23. def printResult():
  24.     text = ""
  25.     total_lines = 0
  26.     for i in line_count:
  27.         total_lines += line_count[i]
  28.     msg = "一共写了【%s】行代码,10万行代码任务的进度为:%.2f%%\n离10万行代码还差【%s】行" % (total_lines, total_lines/1000, 100000-total_lines)
  29.     for i in code_type_dict:
  30.         text += "【%s】类型的文件有 %s 个,共有【%s】行\n" % (i, code_type_dict[i], line_count[i])
  31.     g.textbox(msg, "代码量统计", text=text)


  32. calculateLines(choiceDir())
  33. printResult()

复制代码


但是对文件夹递归问题处理时,还有一种方法,就是使用os.walk,代码如下(没有排除venv文件夹):
  1. import os
  2. import easygui as g

  3. code_list = [".py", ".java", ".asm"]
  4. code_type_dict = {}
  5. line_count = {}


  6. def choiceDir():
  7.     start_path = g.diropenbox(title="请选择起始目录")
  8.     return start_path


  9. def calculateLines(start_path):
  10.     os.chdir(start_path)
  11.     all_files = os.walk(os.getcwd())
  12.     for i in all_files:
  13.         for each_file in i[2]:
  14.             code_type = os.path.splitext(each_file)[1]
  15.             if code_type not in code_list:
  16.                 continue
  17.             code_type_dict.setdefault(code_type, 0)
  18.             code_type_dict[code_type] += 1
  19.             line_count.setdefault(code_type, 0)
  20.             for eachline in each_file:
  21.                 line_count[code_type] += 1


  22. def printResult():
  23.     text = ""
  24.     total_lines = 0
  25.     for i in line_count:
  26.         total_lines += line_count[i]
  27.     msg = "一共写了【%s】行代码,10万行代码任务的进度为:%.2f%%\n离10万行代码还差【%s】行" % (total_lines, total_lines/1000, 100000-total_lines)
  28.     for i in code_type_dict:
  29.         text += "【%s】类型的文件有 %s 个,共有【%s】行\n" % (i, code_type_dict[i], line_count[i])
  30.     g.textbox(msg, "代码量统计", text=text)


  31. calculateLines(choiceDir())
  32. printResult()

复制代码

但是os.walk这种方法我不知道该怎么排除特定文件夹,求大佬指点一下

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 15:47:22 | 显示全部楼层
i[1]就是dirs,判断Venv是不是在i[1]里再往下判断
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 18:05:11 | 显示全部楼层
可以试试这样:
for root,dirs,files in os.walk('...'): #os.walk返回的结果是一个三元的tuple, root是当前要处理的目录,dirs是这个root下的子目录,files是root下的文件
        if root!='...':
           #继续处理的代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 18:20:15 | 显示全部楼层
本帖最后由 喜欢吃菠菜 于 2018-11-11 22:27 编辑

参考一下我的这个代码:
参考一下:
import os
def searchfile(start_dir,extlist):
    video_list=[]
    for root,dir,files in os.walk(start_dir):
        video_list.extend(os.path.join(root,file+'\n') for file in files if file.endswith(extlist))
    return video_list

if __name__=='__main__':
        start_dir=input('请输入要查找的路径:')
        extlist=('.mp4','.avi','.rmvb') #这里用tuple才可以,不要用list,因为endswith的参数要tuple
        program_dir=os.getcwd()
        with open(program_dir+os.sep+'videolist.txt','w') as f:
                    f.writelines(searchfile(start_dir,extlist))
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 21:41:51 | 显示全部楼层
喜欢吃菠菜 发表于 2018-11-11 18:20
参考一下我的这个代码:
参考一下:
import os

file+'\n' 这个‘\n'没看懂  指教一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 21:56:41 | 显示全部楼层
孤星破红尘 发表于 2018-11-11 21:41
file+'\n' 这个‘\n'没看懂  指教一下

这个写法不太懂 extend不是要求参数为一个列表嘛 求指点
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 22:14:13 | 显示全部楼层
这个加\n是为了让找到的一个路径成为一行。调用writelines的时候,在文件中就可以一个路径一行了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 22:17:16 | 显示全部楼层
孤星破红尘 发表于 2018-11-11 21:56
这个写法不太懂 extend不是要求参数为一个列表嘛 求指点

为什么用extend(),因为‘os.path.join(root,file+'\n') for file in files if file.endswith(ext list)’是一个生成器推导式,并不是单个的,所以不能append,应该extend
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-11-11 22:25:18 | 显示全部楼层
喜欢吃菠菜 发表于 2018-11-11 18:05
可以试试这样:
for root,dirs,files in os.walk('...'): #os.walk返回的结果是一个三元的tuple, root是当 ...

老哥 按照你的方法,我将代码修改为了:
    os.chdir(start_path)
    all_files = os.walk(os.getcwd())
    for i in all_files:
        if os.path.split(i[0])[1] != "venv":  #os.path.split(i[0])[1]为root去掉路径的目录名
            for each_file in i[2]:
                code_type = os.path.splitext(each_file)[1]
                if code_type not in code_list:
                    continue
                code_type_dict.setdefault(code_type, 0)
                code_type_dict[code_type] += 1
                line_count.setdefault(code_type, 0)
                for eachline in each_file:
                    line_count[code_type] += 1

但是并不能排除venv文件夹下的文件
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 22:27:10 | 显示全部楼层
孤星破红尘 发表于 2018-11-11 21:56
这个写法不太懂 extend不是要求参数为一个列表嘛 求指点

我的解释你能明白吗?‘os.path.join(root,file+'\n') for file in files if file.endswith(ext list)’在作为extend()的参数时,你可以省去推导式的[]或者(),这样代码看起来更简洁一点
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-11-11 22:28:21 | 显示全部楼层
塔利班 发表于 2018-11-11 15:47
i[1]就是dirs,判断Venv是不是在i[1]里再往下判断

感谢大佬回复,但是venv在i[1]的时候,进行循环的所有文件(也就是files in i[2])不是和venv平级的文件,而不是venv文件夹下的文件吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 22:30:38 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 22:31:45 | 显示全部楼层
本帖最后由 喜欢吃菠菜 于 2018-11-11 22:33 编辑
久光 发表于 2018-11-11 22:28
感谢大佬回复,但是venv在i[1]的时候,进行循环的所有文件(也就是files in i[2])不是和venv平级的文件 ...


不用判断venv在i[1]里面,实际你直接判断i[0]是否是venv就可以了
因为walk本身就是一个递归过程,它的参数就是i[0].
我是这样理解的,你可以试试看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-11-11 22:39:31 | 显示全部楼层
喜欢吃菠菜 发表于 2018-11-11 22:31
不用判断venv在i[1]里面,实际你直接判断i[0]是否是venv就可以了
因为walk本身就是一个递归过程,它的 ...

大哥我回复你的在9楼,判断os.path.split(i[0])[1]是否为“venv”的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 22:40:41 | 显示全部楼层
喜欢吃菠菜 发表于 2018-11-11 22:27
我的解释你能明白吗?‘os.path.join(root,file+'\n') for file in files if file.endswith(ext list)’ ...

‘os.path.join(root,file+'\n') for file in files if file.endswith(ext list)’ 加上()或[] 我理解 是推导式  作为参数的时候还能把括号去掉的嘛
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 23:08:16 | 显示全部楼层
孤星破红尘 发表于 2018-11-11 22:40
‘os.path.join(root,file+'\n') for file in files if file.endswith(ext list)’ 加上()或[] 我理解  ...

你可以试一下看一下吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 23:27:16 | 显示全部楼层
久光 发表于 2018-11-11 22:25
老哥 按照你的方法,我将代码修改为了:
    os.chdir(start_path)
    all_files = os.walk(os.getcwd ...

你的代码太多用一些数字的东西,还有命名不是很清晰,所以理解起来有点混乱。
建议这样改:
for root,dirs,files in walk(os.getcwd()):
    if os.path.split(root)[-1]!='venv':
        for file in files:
            if file.endswith(tuple(code_list)):#最好起一个贴切的变量名,比如extlists等
                ... #剩下的就是你处理你的字典的代码了

仅供参考
     
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-11 23:36:17 | 显示全部楼层
本帖最后由 喜欢吃菠菜 于 2018-11-11 23:58 编辑
孤星破红尘 发表于 2018-11-11 22:40
‘os.path.join(root,file+'\n') for file in files if file.endswith(ext list)’ 加上()或[] 我理解  ...

举个栗子给你参考一下:
  1. l=[1,2,3]
  2. l1=[1,2,3,4,5,6,7,8,9,10]
  3. #把l1中的偶数加到l中
  4. l.extend([i for i in l1 if i % 2==0]) #按正常是这样
  5. l.extend(i for i in l1 if i % 2==0) #也可以这样,更简洁
复制代码

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-11-12 12:34:59 | 显示全部楼层
喜欢吃菠菜 发表于 2018-11-11 23:27
你的代码太多用一些数字的东西,还有命名不是很清晰,所以理解起来有点混乱。
建议这样改:
for root,d ...

这样并不可以排除venv的内容。。。你试一下就知道了,这个和我9l的代码其实是一样的,不过你的变量命名确实比我清晰很多
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-11-12 13:02:16 | 显示全部楼层
如果只是跳过venv目录,这个代码可以的啊。我试过了。
实在不行,你私信我,我看看。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-16 15:07

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表