鱼C论坛

 找回密码
 立即注册
查看: 5605|回复: 12

[学习笔记] 【Pyhon 030讲心得体会】【 查找文件和递归调用返回上一级】

[复制链接]
发表于 2018-11-27 14:44:53 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 heidern0612 于 2018-12-28 09:42 编辑

写心得的过程都是自我思考的过程,借鉴了论坛很多前辈的回答和方法,如有错误,恳请指出,不胜感激!!!


这一讲课后习题很艰难,想到有点昏头涨脑,老师给的答案如果对指令不太敏感的话,也比较难以理解。

有些指令学的似是而非,还是用的比较少的缘故,所以这一讲之后决定暂时先静下心来,花半个月的时间,努力先打好基础再往后面写。



小插曲之笑尿:打dict的时候,总是不自主的打成dick,卧槽我就这么跟脏话有缘?



PS:如果字比较小,请按下CTRL+鼠标滚轮缩放字体大小,不谢。


0、编写一个程序,统计当前目录下每个文件类型的文件数


佳宇老师思路分析:

1、把指针指定在当前目录,列出所有目录下的文件名;用dict()函数创建一个字典,赋值给type_dict。

2、for循环遍历当前目录所有文件名,判断当前文件是否是文件夹:

         是:创建字典默认值,并且字典里唯一的键(key)‘文件夹’的值'0'自增1,此步骤用于统计文件夹数量。

         否:用splittext分离文件名和后缀名,把后缀名指定给ext变量,创建字典默认值,ext(后缀名=文件类型)对应键的值自增1,此步骤用于统计文件类型数量。

3、for循环遍历type_dict的键,打印出来键和键所对应的值。


                        *有的同学可能有点迷糊,key怎么能自增1 ?什么意思不明白。

                        这里key自增1,自增的是自己的value值,而不是key值。

                        字典访问key的时候,访问的不是自己的value吗?



import os

all_files = os.listdir(os.curdir)                                         # listdir列出当前目录所有文件名,有点dos基础的同学应该都不迷糊,curdir指定当前目录。
type_dict = dict()

for each_file in all_files:
    if os.path.isdir(each_file):                                        # 判断指定路径是否存在且是一个目录
        type_dict.setdefault('文件夹', 0)                        #如果键不存在于字典中,将会添加键并将值设置为默认值
        type_dict['文件夹'] += 1
    else:
        ext = os.path.splitext(each_file)[1]                        #分离文件名与后缀名 [0]文件名,[1]后缀名
        type_dict.setdefault(ext, 0)
        type_dict[ext] += 1

for each_type in type_dict.keys():
    print('该文件夹下共有类型为【%s】的文件 %d 个' % (each_type, type_dict[each_type]))



1、编写一个程序,计算当前文件夹下所有文件的大小,这两道题思路差不多,我就缩写了。

佳宇老师思路分析:

1、把指针指定在当前目录,列出所有目录下的文件名,赋值给变量all_files;创建一个空字典。

2、for循环遍历当前目录所有文件名,判断当前文件是否是文件:

         是:统计文件大小,将其赋值给字典中[each_file]键对应的值。

3、for循环遍历file_dict.items,打印出来键和键所对应的值。

import os

all_files = os.listdir(os.curdir) 
file_dict = dict()

for each_file in all_files:
    if os.path.isfile(each_file):                                        #判断指定路径是否存在且是一个文件
        file_size = os.path.getsize(each_file)
        file_dict[each_file] = file_size

for each in file_dict.items():
    print('%s【%dBytes】' % (each[0], each[1]))






2、 编写一个程序,用户输入文件名以及开始搜索的路径,搜索该文件是否存在。如遇到文件夹,则进入文件夹继续搜索,程序实现如图:


佳宇老师思路分析:

1、定义一个函数,两个形参,改变当前目录为用户Input输入目录。

2、for循环遍历当前用户输入目录下所有文件名:

        A、如果each_file和用户输入文件名相比较,名字相等,打印当前目录+分隔符+当前文件名;

        B、如果each_file循环到的是个文件夹的话,调用递归,再次搜索目标文件,返回上一级目录。

                  *:这里为何要返回上一级的目的一是为了防止文件夹是个空文件夹,没有目标文件,二是为了防止例如三级和四级目录下有相同目标文件的情况。

                      跳出递归的关键是,递归到each_file是文件的时候,就不会调用递归(当前目录下只有一个文件,没有文件夹)。

                      这个时候肯定要返回上一级目录,进行下一次文件和文件夹的判断。
import os

def search_file(start_dir, target) :                        
    os.chdir(start_dir)                                                                # 改变工作目录
    
    for each_file in os.listdir(os.curdir) :
        if each_file == target :
            print(os.getcwd() + os.sep + each_file)                         #  getcwd返回当前工作目录 sep输出操作系统路径分隔符
        if os.path.isdir(each_file) :                                                #判断指定路径是否存在且是一个目录
            search_file(each_file, target)                                         # 递归调用
            os.chdir(os.pardir)                                                         # 递归调用后切记返回上一层目录

start_dir = input('请输入待查找的初始目录:')
target = input('请输入需要查找的目标文件:')
search_file(start_dir, target)


另类实现:
import os
def getRoutes(dest_dir, dest_file):
    for root, dirs, files in os.walk(dest_dir):
        for file in files:
            if file == dest_file:
                print('%s\%s' % (root, file))
dest_dir = input('请输入待查找的初始目录:')
dest_file = input('请输入待查找的目标文件:')
getRoutes(dest_dir, dest_file)



3、编写一个程序,用户输入开始搜索的路径,查找该路径下(包含子文件夹内)所有的视频格式文件(要求查找mp4 rmvb, avi的格式即可),并把创建一个文件(vedioList.txt)存放所有找到的文件的路径,程序实现如图:


如果上面三道题认真看老师思路的同学,这道题应该比较好理解,就不多说了。
import os

def search_file(start_dir, target) :
    os.chdir(start_dir)
    
    for each_file in os.listdir(os.curdir) :
        ext = os.path.splitext(each_file)[1]
        if ext in target :
            vedio_list.append(os.getcwd() + os.sep + each_file + os.linesep)                 # 使用os.sep是程序更标准
        if os.path.isdir(each_file) :
            search_file(each_file, target)                         # 递归调用
            os.chdir(os.pardir)                                         # 递归调用后切记返回上一层目录

start_dir = input('请输入待查找的初始目录:')
program_dir = os.getcwd()

target = ['.mp4', '.avi', '.rmvb']
vedio_list = []

search_file(start_dir, target)

f = open(program_dir + os.sep + 'vedioList.txt', 'w')
f.writelines(vedio_list)
f.close()

另类实现:
import os
def saveRoutes():
    dest_dir = input('请输入待查找的初始目录:')
    dest_suffix = input('请输入目标文件后缀:')
    f = open('output.txt', 'w')
    for root, dirs, files in os.walk(dest_dir):
        for file in files:
            suffix = os.path.splitext(file)[1]
            if suffix == dest_suffix:
                f.write('%s\%s
' % (root, file))
    f.close()




4、编写一个程序,用户输入关键字,查找当前文件夹内(如果当前文件夹内包含文件夹,则进入文件夹继续搜索)所有含有该关键字的文本文件(.txt后缀),要求显示该文件所在的位置以及关键字在文件中的具体位置(第几行第几个字符),程序实现如图:


想了一下午,想的头疼。

这一题比较晦涩难明,所以我解释详细一点,看第一个函数的时候一头雾水,有木有?

什么JB玩意一大串的看不明白,环顾这道题,其实这道题是要倒着来看的,从代码末尾的主函数开始理解,细化到开始的打印分支函数。

首先请先理解下这两个函数的概念:   A、猛击前往os.walk( )方法概念                B、猛击前往find( )方法概念


OS.walk如果还不知道返回的什么是三元组,偷偷告诉你,返回的就是:0、当前的路径  ; 2、当前的文件夹  ;  3、当前的文件;

老师课堂上根本木有讲有木有?确定大致理解了什么意思,再往下看。



佳宇老师思路(从大到小依次细化:主模块--->分模块--->小模块):

1、调用主函数search_files(主模块),从当前目录中查找可打开的txt文件,并询问是否需要print详细;

                需要的话调用print_pos函数(额外分支模块)。

2、调用函数search_in_file(主模块下的分模块),从当前文件查找关键字,如果关键字在某一行中,调用pos_in_line函数(分模块下的小模块)。

3、调用函数pos_in_line函数查找关键字所在的位置,依次上返。


其实说白了这道题更像是嵌套的结构,主模块嵌套(调用)分模块,分模块(调用)嵌套小模块。

主函数在处理的过程中遇到问题调用分支函数,分支函数在处理的过程中遇到问题调用更细的分支函数。



代码分析如下:
import os



#================打印结果==================
#此函数主用于search_files函数需要打印具体位置时,调用此函数将字典类型排序,打印对应行数及位置。

def print_pos(key_dict):
    keys = key_dict.keys()                                #分离字典的key
    keys = sorted(keys)                                 # 由于字典是无序的,我们这里对行数进行排序
    for each_key in keys:
        print('关键字出现在第 %s 行,第 %s 个位置。' % (each_key, str(key_dict[each_key])))





#================在某行查找关键字==================
#此函数主用于定位关键字所在行的位置,返给serch_in_file写入字典value.

def pos_in_line(line, key):
    pos = []
    begin = line.find(key)                                 #查找关键字在每一行中的位置,赋值给begin
    while begin != -1:                                        #不为-1时代表找到了,建议了解下find函数。
        pos.append(begin + 1)                                 # 用户的角度是从1开始数
        begin = line.find(key, begin+1)                 # 从下一个位置继续查找

    return pos




#================在文件中查找==================
#此函数主用于将文件以行数为索引的key,关键字在行的位置作为value作为字典类型,调用pos_in_line函数处理,将字典返回给search_files函数。

def search_in_file(file_name, key):
    f = open(file_name)                                                 #打开文本文件
    count = 0                                                         # 记录行数
    key_dict = dict()                                                 # 定义字典,用户存放key所在具体行数对应具体位置
    
    for each_line in f:                                                 #遍历文本文件中的每一行
        count += 1                                                   #行数记录
        if key in each_line:                                        #如果关键字在某一行中
            pos = pos_in_line(each_line, key)                 # key在每行对应的位置  调用pos_in_line函数 传入这个行和关键字
            key_dict[count] = pos
    
    f.close()
    return key_dict





#================主程序(在目录中查找)==================
#此函数主用于遍历当前目录下可以打开的txt文档,然后调用search_in_file函数进行处理。


def search_files(key, detail):                                                    #第一步调用search_file函数 把 key, detail 参数传入进去
    all_files = os.walk(os.getcwd())                                                 #遍历当前目录下的所有文档,返回一个三目元祖(1.目录,2.包含路径,3.包含文件),将返回的结果赋值给all_files
    txt_files = []                                                                         #定义列表txt_files 

    for i in all_files:                                                                 #遍历all_files  注意这里的i为单次遍历的三元组,也就是说,这里的i是包含目录、路径和文件的三元组。
        for each_file in i[2]:                                                         #遍历三元组的第三个值,即遍历文件,这里的each_file为单次遍历的文件
            if os.path.splitext(each_file)[1] == '.txt':                         # 根据后缀判断是否文本文件
                each_file = os.path.join(i[0], each_file)                         #如果each_file 是文本文件  则将该文件的路径名称以及文件名称合并,并赋值给each_file 
                txt_files.append(each_file)                                         #列表txt_files 中追加each_file 此时的each_file为全路径含文件名 列表中追加的文本文件全路径

    for each_txt_file in txt_files:                                                #在列表txt_file中 遍历所有的文本文件 each_txt_file为单次遍历的文本文件名
        key_dict = search_in_file(each_txt_file, key)                        #调用seach_in_file函数,传入单次遍历的文本文件名each_txt_file和用户输入的关键字key
        if key_dict:
            print('================================================================')
            print('在文件【%s】中找到关键字【%s】' % (each_txt_file, key))
            if detail in ['YES', 'Yes', 'yes']:
                print_pos(key_dict)

key = input('请将该脚本放于待查找的文件夹内,请输入关键字:')                                                         #接受用户输入的关键字 key为用户输入的结果
detail = input('请问是否需要打印关键字【%s】在文件中的具体位置(YES/NO):' % key)                         #请示用户是否打印  detail为请示结果
search_files(key, detail)                                                                                                                 #调用函数search_files 传入关键字 key, detail 



剩下难以理解的就是各个函数、方法灵活的运用了。

                如果我写成这样有的同学还不理解,自己把之前几课关于os相关的代码不照着敲,摸索着敲个几遍,大概就能理解了。

                *:不照着敲的意思就是不对着屏幕和书本代码一个一个的敲,按自己理解回忆着去敲。

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2018-12-27 15:14:41 From FishC Mobile | 显示全部楼层
加油
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-2-14 23:45:30 | 显示全部楼层
感谢大佬讲解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-6-1 10:23:40 | 显示全部楼层
我照着运行之后出现了如下问题,请哪位大佬帮我找找原因?我文本文件里列举了几行汉字保存为utf-8格式都试过了
Traceback (most recent call last):
  File "C:\Users\dybhh\Desktop\pypractice\030-5.py", line 51, in <module>
    search_files(key,detail)
  File "C:\Users\dybhh\Desktop\pypractice\030-5.py", line 42, in search_files
    key_dict = search_in_file(each_txt_file,key)
  File "C:\Users\dybhh\Desktop\pypractice\030-5.py", line 23, in search_in_file
    for each_line in f:
UnicodeDecodeError: 'gbk' codec can't decode byte 0xff in position 0: illegal multibyte sequence
>>>
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2020-4-16 21:56:45 From FishC Mobile | 显示全部楼层
感谢大佬
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-1 14:28:06 | 显示全部楼层
谢谢精心的整理,很有帮助!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-2 17:23:57 | 显示全部楼层
空字典的布尔类型为False,所以不会打印~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-7 20:08:17 | 显示全部楼层
感谢感谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-8 13:37:44 | 显示全部楼层
您好,想请教您一个问题
2、 编写一个程序,用户输入文件名以及开始搜索的路径,搜索该文件是否存在。如遇到文件夹,则进入文件夹继续搜索

关于这道题的第10行代码 search_file(each_file, target) #调用递归
each_file 不是只是一个字符串么 比如 ‘新建文件夹1号’ 这种样子
运行os.chdir(start_dir) 为什么不会报错说找不到呢?我试了一下os.chdir(‘新建文件夹’)会显示找不到地方
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-5-8 16:22:57 | 显示全部楼层
兔兔熊 发表于 2020-5-8 13:37
您好,想请教您一个问题
2、 编写一个程序,用户输入文件名以及开始搜索的路径,搜索该文件是否存在。如遇 ...

我发了个悬赏贴~您需要鱼币的话可以去我的帖子里回答,谢谢您了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-8-9 12:19:09 | 显示全部楼层
感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-8-10 21:45:15 | 显示全部楼层
感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-9-16 11:08:45 | 显示全部楼层
我第二题一开始用小甲鱼老师的方法做,没加返回上一层目录,后来使用的是绝对路径做的,就不用来回跳转了。在您这搞明白那句话作用了,谢谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-22 08:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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