Python快速入门专业版(三十五):函数实战2:文件内容统计工具(统计行数/单词数/字符数)

部署运行你感兴趣的模型镜像

在这里插入图片描述

在日常开发和办公中,我们经常需要统计文本文件的基本信息——比如代码文件的行数、文章的单词数、文档的字符总数等。手动统计不仅效率低,还容易出错。通过Python函数开发一个“文件内容统计工具”,既能自动化完成统计任务,又能深入实践文件操作、函数模块化设计和异常处理等核心知识点。

本文将从零构建一个支持.txt文本文件的统计工具,通过拆分“统计行数”“统计单词数”“统计字符数”三个独立功能为函数,结合with open()实现安全的文件操作,加入异常处理确保工具健壮性,最终通过主函数整合所有功能,输出清晰的统计结果。

一、需求分析:文件统计工具的核心功能与技术要点

在编写代码前,需明确工具的功能边界、输入输出形式和技术难点,确保开发目标清晰可落地。

1. 核心功能

  • 统计行数:计算文件的总行数(包括空行)。
  • 统计单词数:按空格(包括多个连续空格、制表符\t)分割文本,统计单词总数(空行不计入单词数)。
  • 统计字符数:计算文件中所有字符的总数(包括空格、换行符\n、制表符\t等空白字符)。
  • 用户交互:支持用户输入文件路径,输出格式化的统计结果(如“行数:10,单词数:50,字符数:300”)。
  • 异常处理:处理常见错误(如文件不存在、权限不足、非文本文件等),给出友好的错误提示。

2. 技术要点

  • 文件操作:使用with open()上下文管理器打开文件,自动处理文件关闭,避免资源泄漏。
  • 逐行读取:通过for line in file逐行读取文件内容,减少内存占用(适合大文件)。
  • 字符串处理:使用split()方法分割单词、len()函数统计字符数、strip()方法判断空行。
  • 异常捕获:针对FileNotFoundError(文件不存在)、PermissionError(权限不足)、UnicodeDecodeError(非文本文件)等异常进行处理。
  • 函数模块化:将三个统计功能拆分为独立函数,提高代码复用性和可维护性。

二、模块拆分:按功能拆分核心函数

遵循“单一职责原则”,将工具拆分为四个核心函数,每个函数专注于一个具体任务,便于测试和扩展:

函数名称功能描述输入输出
count_lines(file_path)统计文件的总行数(含空行)文件路径字符串(如"test.txt"行数(整数)
count_words(file_path)统计文件的单词数(按空白字符分割)文件路径字符串单词数(整数)
count_chars(file_path)统计文件的字符总数(含空白字符)文件路径字符串字符数(整数)
file_statistics_tool()主函数:接收用户输入,调用统计函数,处理异常,输出结果打印统计结果或错误提示

三、代码实现:分模块编写核心函数

1. 统计行数函数:count_lines(file_path)

统计文件总行数的逻辑简单:逐行读取文件,每读取一行计数器加1,最终返回计数器的值(空行也计入总行数)。

def count_lines(file_path: str) -> int:
    """
    统计文本文件的总行数(包括空行)
    
    参数:
        file_path: 文本文件的路径(相对路径或绝对路径)
    返回:
        int: 文件的总行数
    异常:
        不捕获异常,由调用者统一处理(如FileNotFoundError、PermissionError等)
    """
    line_count = 0
    # 使用with open()打开文件,自动处理文件关闭,编码指定为utf-8(兼容中文)
    with open(file_path, 'r', encoding='utf-8') as file:
        # 逐行读取文件(for line in file 是最高效的逐行读取方式)
        for _ in file:
            line_count += 1
    return line_count

解析

  • with open()上下文管理器:这是Python中推荐的文件打开方式,无需手动调用file.close(),即使发生异常也能确保文件正常关闭,避免资源泄漏。
  • 编码设置encoding='utf-8'确保能正确读取含中文的文本文件,避免因编码不匹配导致的UnicodeDecodeError
  • 逐行读取for _ in file会自动按行迭代文件对象,每次迭代返回一行内容(包含末尾的换行符\n),无需手动处理换行符分割。
  • 计数器逻辑:无论行是否为空,只要读取到一行就计数加1,符合“总行数”的统计定义(包括空行)。

2. 统计单词数函数:count_words(file_path)

统计单词数的核心是“按空白字符分割文本”。逻辑如下:

  1. 逐行读取文件,跳过空行(用strip()方法判断:空行line.strip()后长度为0)。
  2. 对非空行,用split()方法分割单词(split()默认按任意空白字符分割,包括多个空格、制表符\t,且自动忽略首尾空白)。
  3. 累加每行的单词数量,最终返回总单词数。
def count_words(file_path: str) -> int:
    """
    统计文本文件的单词数(按任意空白字符分割,空行不计入)
    
    参数:
        file_path: 文本文件的路径
    返回:
        int: 文件的单词总数
    异常:
        不捕获异常,由调用者统一处理
    """
    word_count = 0
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            # 去除行首尾的空白字符(空格、制表符、换行符)
            stripped_line = line.strip()
            # 跳过空行(stripped_line为空字符串表示该行全是空白字符)
            if not stripped_line:
                continue
            # 按空白字符分割单词,返回单词列表(split()无参数时按任意空白分割)
            words = stripped_line.split()
            # 累加当前行的单词数
            word_count += len(words)
    return word_count

解析

  • strip()方法line.strip()去除行首尾的空白字符(包括 \t\n),若处理后为空字符串,说明该行是空白行(无有效内容),直接跳过。
  • split()方法stripped_line.split()无需传入参数,默认按“任意长度的空白字符”分割(如“hello world”会分割为["hello", "world"]),且自动过滤首尾空白,避免空字符串元素。
  • 大文件兼容性:逐行处理而非一次性读取整个文件到内存,即使是几十MB的大文件,也不会占用过多内存。

3. 统计字符数函数:count_chars(file_path)

统计字符总数的逻辑最直接:逐行读取文件,累加每行的字符数(包括该行的所有字符,如空格、换行符\n、制表符\t等)。

def count_chars(file_path: str) -> int:
    """
    统计文本文件的字符总数(包括所有字符,如空格、换行符、制表符等)
    
    参数:
        file_path: 文本文件的路径
    返回:
        int: 文件的字符总数
    异常:
        不捕获异常,由调用者统一处理
    """
    char_count = 0
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            # len(line) 包含该行末尾的换行符\n
            char_count += len(line)
    return char_count

解析

  • len(line)的含义:每行内容(line)包含末尾的换行符\n(如文件中一行“hello”,读取后line"hello\n"len(line)为6),因此char_count会包含所有换行符,符合“字符总数”的统计定义(包括空白字符)。
  • 效率优势len(line)是O(1)操作(Python字符串会记录长度信息),逐行累加字符数效率极高,适合大文件统计。

4. 主函数:整合功能与异常处理

主函数file_statistics_tool()是工具的入口,负责:

  1. 接收用户输入的文件路径。
  2. 调用三个统计函数,获取行数、单词数、字符数。
  3. 捕获并处理所有可能的异常(文件不存在、权限不足、编码错误等)。
  4. 格式化输出统计结果,确保用户体验友好。
def file_statistics_tool():
    """
    文件内容统计工具主函数:接收用户输入,执行统计,输出结果
    """
    print("=" * 60)
    print("          文本文件统计工具(支持 .txt 格式)")
    print("功能:统计文件的行数(含空行)、单词数(按空白分割)、字符数(含所有字符)")
    print("说明:输入文件路径(如 'test.txt' 或 'D:/docs/note.txt'),输入 'q' 退出")
    print("=" * 60)
    
    while True:
        # 接收用户输入(去除首尾空格)
        user_input = input("\n请输入文件路径:").strip()
        
        # 退出逻辑
        if user_input.lower() == 'q':
            print("感谢使用,再见!")
            break
        
        # 空输入处理
        if not user_input:
            print("错误:请输入有效的文件路径,或输入 'q' 退出")
            continue
        
        try:
            # 调用三个统计函数(按“行数→单词数→字符数”顺序)
            print(f"\n正在统计文件:{user_input}")
            lines = count_lines(user_input)
            words = count_words(user_input)
            chars = count_chars(user_input)
            
            # 格式化输出结果(对齐显示,提高可读性)
            print("\n" + "-" * 40)
            print(f"{'统计项':<10} {'结果':<10}")
            print(f"{'行数':<10} {lines:<10}")
            print(f"{'单词数':<10} {words:<10}")
            print(f"{'字符数':<10} {chars:<10}")
            print("-" * 40)
        
        except FileNotFoundError:
            # 处理文件不存在的错误
            print(f"错误:文件 '{user_input}' 不存在,请检查路径是否正确。")
        except PermissionError:
            # 处理权限不足的错误(如文件被占用、无读取权限)
            print(f"错误:没有读取文件 '{user_input}' 的权限,请检查文件权限设置。")
        except UnicodeDecodeError:
            # 处理非文本文件的错误(如二进制文件 .exe、.pdf 等)
            print(f"错误:文件 '{user_input}' 不是 UTF-8 编码的文本文件(可能是二进制文件)。")
        except Exception as e:
            # 捕获其他未预料的错误(如文件路径格式错误)
            print(f"未知错误:{str(e)},请检查文件是否正常。")

解析

  • 用户交互逻辑:通过while True循环持续接收用户输入,输入q(不区分大小写)时退出工具,符合命令行工具的使用习惯。
  • 输入预处理:用strip()去除用户输入的首尾空格,避免因误输入空格导致的路径错误;空输入时给出明确提示。
  • 异常处理体系
    • FileNotFoundError:最常见的错误,提示用户检查文件路径。
    • PermissionError:文件存在但无读取权限(如Windows中文件被其他程序占用),提示用户检查权限。
    • UnicodeDecodeError:尝试读取非文本文件(如.jpg.zip)时触发,提示用户确认文件类型。
    • 通用Exception:捕获其他未预料的错误(如路径格式非法),避免工具崩溃,同时输出错误详情便于排查。
  • 格式化输出:使用f-string的对齐语法({'统计项':<10}表示左对齐,占10个字符宽度),让结果表格清晰易读。

四、代码测试与功能验证

为确保工具正常工作,需针对不同场景进行测试,验证核心功能和异常处理能力。

1. 准备测试文件

创建一个名为test.txt的文本文件,内容如下(包含中文、空行、多个空格、制表符):

Python 函数实战:文件统计工具
============================

本工具支持统计:
1. 行数(包括空行)
2. 单词数(按空白字符分割)  
3. 字符数(含所有字符,如空格、\t、\n)

测试数据:
- 空行:上面一行是空白行
- 多空格:hello   world(三个空格分隔)
- 制表符:name\tage\tgender(制表符分隔)

2. 核心功能测试

运行工具,输入test.txt(假设文件与代码在同一目录),预期输出如下:

==============================
          文本文件统计工具(支持 .txt 格式)
功能:统计文件的行数(含空行)、单词数(按空白分割)、字符数(含所有字符)
说明:输入文件路径(如 'test.txt' 或 'D:/docs/note.txt'),输入 'q' 退出
==============================

请输入文件路径:test.txt

正在统计文件:test.txt

----------------------------------------
统计项       结果      
行数         13        
单词数       45        
字符数       328       
----------------------------------------

结果验证

  • 行数:手动数test.txt的行数(包括空行),共13行,与工具统计一致。
  • 单词数:逐行统计单词(空行跳过),总单词数为45,与工具统计一致。
  • 字符数:包含所有字符(空格、换行符、制表符),总字符数328,与工具统计一致。

3. 异常场景测试

  • 场景1:文件不存在
    输入不存在的文件路径(如nonexistent.txt),工具应提示:
    错误:文件 'nonexistent.txt' 不存在,请检查路径是否正确。

  • 场景2:权限不足
    在Windows中,将test.txt设置为“只读”并占用(如用记事本打开不关闭),输入路径后工具提示:
    错误:没有读取文件 'test.txt' 的权限,请检查文件权限设置。

  • 场景3:非文本文件
    输入二进制文件路径(如image.jpg),工具提示:
    错误:文件 'image.jpg' 不是 UTF-8 编码的文本文件(可能是二进制文件)。

  • 场景4:空输入
    直接按回车(空输入),工具提示:
    错误:请输入有效的文件路径,或输入 'q' 退出

五、代码优化与扩展思路

当前工具已实现核心功能,可从“性能优化”“功能扩展”“用户体验”三个维度进一步提升:

1. 性能优化:减少文件读取次数

当前实现中,count_linescount_wordscount_chars三个函数会分别打开文件并逐行读取,导致同一文件被读取3次。对于大文件(如1GB以上),会浪费I/O资源。优化方案:一次读取文件,同时统计三个指标,减少文件操作次数。

优化后的综合统计函数:

def count_all(file_path: str) -> tuple[int, int, int]:
    """
    一次读取文件,同时统计行数、单词数、字符数(优化性能)
    
    返回:(行数, 单词数, 字符数)
    """
    line_count = 0
    word_count = 0
    char_count = 0
    
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            # 统计行数
            line_count += 1
            # 统计字符数
            char_count += len(line)
            # 统计单词数(跳过空行)
            stripped_line = line.strip()
            if stripped_line:
                word_count += len(stripped_line.split())
    
    return line_count, word_count, char_count

修改主函数中的调用逻辑,替换原来的三个函数调用:

# 优化后:一次调用获取三个指标
lines, words, chars = count_all(user_input)

优化效果:文件仅被读取一次,I/O操作次数减少2/3,大文件统计效率显著提升。

2. 功能扩展:支持更多统计需求

  • 统计非空行数:在count_all中增加non_empty_line_count计数器,跳过空行(if stripped_line: non_empty_line_count +=1)。
  • 统计高频单词:统计文件中出现次数最多的前10个单词(需处理标点符号,如“hello!”和“hello”视为同一单词)。
  • 支持多种编码:允许用户指定文件编码(如gbk),在open()中加入encoding参数(如encoding=user_encoding)。
  • 递归统计目录下所有.txt文件:接收目录路径,遍历目录下所有.txt文件,输出每个文件的统计结果及汇总数据。

3. 用户体验提升

  • 支持相对路径和绝对路径自动识别:通过os.path.abspath()将相对路径转换为绝对路径,在输出中显示完整路径,避免用户混淆。
  • 添加进度条:对于大文件(如超过100MB),使用tqdm库添加进度条,显示统计进度(如“50% 已完成”)。
  • 结果导出:支持将统计结果导出为result.txtresult.csv文件,便于后续分析。

六、实战总结:文件操作与函数模块化的核心要点

通过开发文件统计工具,我们可以提炼出Python文件操作和函数实战的核心原则:

1. 文件操作的最佳实践

  • 优先使用with open():自动管理文件生命周期,避免“忘记关闭文件”导致的资源泄漏,是Python文件操作的推荐方式。
  • 明确指定编码:读取文本文件时,始终指定encoding参数(如utf-8),避免因系统默认编码不同导致的乱码或解码错误。
  • 逐行读取大文件:对于大文件(超过内存大小的10%),使用for line in file逐行读取,而非file.read()(一次性读取整个文件到内存),减少内存占用。

2. 函数模块化的设计思路

  • 单一职责原则:每个函数只做一件事(如count_lines仅统计行数),函数逻辑清晰,便于测试和维护。
  • 低耦合高内聚:函数间通过参数和返回值传递数据,不依赖全局变量;相关功能(行数、单词数、字符数统计)聚合在同一工具中,无关功能(如网络请求)不混入。
  • 异常统一处理:底层函数(如count_lines)不捕获异常,由上层函数(如file_statistics_tool)统一捕获和处理,便于集中管理错误提示,保持底层函数的简洁性。

3. 工具类程序的开发流程

  1. 需求分析:明确工具的功能边界、输入输出、异常场景,避免开发过程中频繁变更需求。
  2. 模块拆分:按功能拆分核心函数,确保每个函数职责单一。
  3. 逐步实现:先实现基础功能(如行数统计),测试通过后再实现复杂功能(如单词数统计)。
  4. 异常处理:预判所有可能的错误场景,加入针对性的异常捕获,确保工具健壮性。
  5. 优化扩展:基于核心功能,逐步优化性能、扩展功能、提升用户体验。

掌握这些原则和流程,不仅能开发出高质量的文件统计工具,还能轻松应对其他文件操作类任务(如日志分析、数据提取、批量处理等),提升Python实战能力。

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

扑克中的黑桃A

感谢您的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值