点击上方蓝色字体,关注程序员zhenguo

你好,我是 zhenguo
这是我的第496篇原创
这是第五个Python小项目,做一个文件定位器。
前四个项目:
查找某目录下所有文件,包含指定查找串的文件。注意,这里不仅仅匹配文件名,而是搜索文件的内容。
为了加快搜索速度,本身这又是一个IO任务,所以选用至多同时存活500个线程的技术,加快搜索进度。

项目环境

使用osthreading内置模块,用于操作目录和文件,多线程相关。
click模块之前介绍过,主要用于封装命令行接口,使用方便。
Python版本是3.7.2
import
 os

import
 threading

import
 click

功能演示

文末下载模块代码后,打开命令行窗口,执行下面一行代码,使用-t指定要查找的关键字线程-p指定查找目录,指在当前目录的父级目录下查找:
python str_finder.py -t 线程 -p ..

打印结果,分割线上是查找的文件,在此没有贴上来。
分割线下面是查找的结果,报告使用多少个线程,同时存活线程数,待查找的关键字线程位于哪些文件中,如下所示:
-------------------------------------------------------------------------

共使用
6
个线程

同时存活线程数
2
线程 found 
in
 ../python-small-examples2/python-small-examples/README.md

线程 found 
in
 ../python-small-examples2/python-small-examples/md/
120.
md

线程 found 
in
 ../python-small-examples2/python-small-examples/md/
121.
md

线程 found 
in
 ../python-small-examples2/python-small-examples/md/
118.
md

线程 found 
in
 ../python-small-examples2/python-small-examples/md/
119.
md

线程 found 
in
 ../python-small-examples2/python-small-examples/md/
122.
md

线程 found 
in
 ../python-small-examples2/python-small-examples/md/
123.
md

线程 found 
in
 ../python-small-examples2/python-small-examples/all.md

线程 found 
in
 ../python-small-projects/Python200小例子.md

线程 found 
in
 ../python-small-projects/str_finder.py

线程 found 
in
 ../
10
个可视化作品-作者zhenguo/作品
15
-Matplotlib动图/爬虫案例.md

再查找雪花,使用下行命令:
python str_finder.py -t 雪花  -p ..

查找结果:
----------------------------------------------------------------------------------------------------

共使用
6
个线程

同时存活线程数
2
雪花 found 
in
 ../python-small-examples2/python-small-examples/README.md

雪花 found 
in
 ../python-small-examples2/python-small-examples/md/
141.
md

雪花 found 
in
 ../python-small-examples2/python-small-examples/all.md

雪花 found 
in
 ../publish-book/视频文字稿.md

雪花 found 
in
 ../python-small-projects/Python200小例子.md

代码逐行解释

项目只由一个模块str_finder.py,模块中包括TextFinder类,下面主要讲解类的组成。

TextFinder类

TextFinder类包括:
三个类属性
对外公开方法get_files
递归私有方法__get_files
线程方法__task
下面分别介绍这四个构建。

类属性

前两个类属性已注释,第三个属性表示查找支持的文件后缀,目前默认为下面4种:
    max_thread_cnt = 
500# 同时存活线程数最大500
    big_byte_file = 
0.05# MB
    ext_list = [
'.csv'
'.txt'
'.md'
'.py'
'.java'
]

对外公开方法get_files

主要包括调用私有方法__get_files
同时,通过join,等待所有线程执行完成后,主线程才开始执行print('-' * 100)及以下代码:
defget_files(self):
        self.__get_files(self.path)

for
 thr 
in
 self.threads:

            thr.join()


        print(
'-'
 * 
100
)

        print(
f'共使用{len(self.threads)}个线程'
)

        print(
f'同时存活线程数{self._live_thread_cnt}'
)

if
 len(self.result) == 
0
:

            print(self.text + 
" not found! "
)

else
:

for
 res 
in
 self.result:

                print(res)

递归私有方法__get_files

递归查找满足后缀的文件
同时存活线程数不能超过默认值,主要考虑内存的负载。
def__get_files(self, path):
        files = os.listdir(path)

for
 name 
in
 files:

            path_name = os.path.join(path, name)

if
 os.path.isdir(path_name):

                self.__get_files(path_name)

if
 self.__in_extensions(name):

                file_byte = os.stat(path_name).st_size / 
1024
 / 
1024
if
 file_byte > TextFinder.big_byte_file:

if
 threading.active_count() < TextFinder.max_thread_cnt:

                        big_file_proc = threading.Thread(target=self.__task, args=(path_name,))

                        big_file_proc.start()

                        self.threads.append(big_file_proc)

                        self._live_thread_cnt = max(self._live_thread_cnt, threading.active_count())

else
:

                        self.__task(path_name)

else
:

                    self.__task(path_name)

线程内的target等于__taskopenread的IO操作适合Python的多线程处理,加快查找:
def__task(self, path_name):
        print(
f'正在查找 {path_name}'
)

        f = open(path_name, 
"r"
)

try
:

if
 self.text 
in
 f.read():

                self.__found_flag = 
True
                self.result.append(
f'{self.text} found in {path_name}'
)

except
 UnicodeDecodeError:

            print(
f'解析错误 {path_name}'
)

封装cmd命令行接口

click模块封装命令行接口的标准用法,如下所示:
@click.command()
@click.option('-t', help='要查找的文本')
@click.option('-p', help='在哪里查找')
def__cmd(t, p):
    TextFinder(t, p).get_files()



if
 __name__ == 
"__main__"
:

    cmd()

项目测试

截止2022年1月13日,未发现有bug

完整代码下载

上面完整py代码文件,可以在我的公众号后台回复:c,即可下载,同时后面的项目代码文件,我也会同步到这个文件夹中,下载方式也是回复c
长按关注,回复c
不用打赏,点个赞或在看

就心满意足了
继续阅读
阅读原文