程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Python 基础

    • Python基础
  • Python 进阶

    • 装饰器与生成器
    • 异常处理
    • 标准库精讲
    • 模块与包
    • pip包管理工具
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
前端 (opens new window)
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Python 基础

    • 环境搭建
    • 标识符
    • 变量
    • 缩进和注释
    • 数据类型
    • 数据类型转换
    • 运算符
    • 字符串
    • 列表
    • 元组
    • 字典
    • 集合
    • if判断
    • for循环
    • while循环
    • 循环综合练习
    • Python函数
    • 函数与循环实战
    • 生成式
    • 文件读写
      • 1. open() 函数
        • 1.1 open() 语法详解
        • 1.2 理解文件路径
        • 1.3 深入理解文件模式 (mode)
        • 1.4 为何 encoding 至关重要?
      • 2. with 语句 (上下文管理器)
      • 3. 写入文件:write() 与 writelines()
        • 3.1 write(string): 写入单个字符串
        • 3.2 writelines(lines): 写入字符串列表
      • 4. 读取文件:三种核心方法
        • 4.1 read(size=-1): 一次性读取
        • 4.2 readlines(): 所有行存入列表
        • 4.3 readline() 与迭代:逐行处理 (最高效)
      • 5. 文件对象的属性
      • 6. 文件指针:seek() 与 tell()
      • 7. 稳健编程:处理文件错误
      • 8. 文件系统管理:os 与 pathlib 模块
        • 8.1 传统方式:os 模块
        • 路径处理 (os.path)
        • 目录操作
        • 文件操作
        • 8.2 现代方式:pathlib 模块 (推荐)
        • 8.3 综合案例:自动整理下载文件夹
        • 版本 A: 使用 os 模块实现
        • 版本 B: 使用 pathlib 模块实现 (更简洁)
      • 9. 综合案例:统计日志中的 IP 地址
    • 面向对象
    • 面向对象综合案例
  • Python 进阶

  • Python
  • Python 基础
scholar
2025-07-20
目录

文件读写

# 文件操作

在几乎所有的编程应用中,我们都需要与文件打交道——读取配置文件、保存用户数据、处理日志、分析数据集等等。文件操作是连接程序与永久性存储(如硬盘)的桥梁,是每个 Python 学习者都必须掌握的核心技能。


# 1. open() 函数

在对文件进行任何操作之前,你必须先“打开”它。Python 内置的 open() 函数负责这个任务,它会返回一个文件对象。这个对象非常强大,它不仅包含了文件的信息,还是一个迭代器和上下文管理器,这为后续的 for 循环和 with 语句提供了基础。

# 1.1 open() 语法详解

file_object = open(file, mode='r', encoding=None)
1
  • file (必需): 文件的路径。
  • mode (可选): 一个字符串,用于指定文件的打开模式。默认为 'r'(只读文本模式)。
  • encoding (可选): 用于编解码文本文件的编码格式。这是处理文本文件时极其重要的参数。

# 1.2 理解文件路径

  • 相对路径 (Relative Path): 从当前脚本所在的位置开始计算。

    • "data.txt": 表示与你的 .py 脚本文件在同一个文件夹下的 data.txt 文件。
    • "data/log.txt": 表示在当前文件夹下的 data 子文件夹中的 log.txt 文件。
  • 绝对路径 (Absolute Path): 从文件系统的根目录开始的完整路径,不受脚本位置影响。

    • Windows: "C:\\Users\\Alice\\Documents\\data.txt" (注意 \ 需要转义成 \\) 或使用原始字符串 r"C:\Users\Alice\Documents\data.txt"。
    • macOS/Linux: "/home/alice/documents/data.txt"。
  • 现代化的路径处理 (推荐):

    from pathlib import Path
    # Path 对象让路径操作更直观、更安全
    data_folder = Path("data")
    file_path = data_folder / "log.txt" # 使用 / 运算符拼接路径
    # with open(file_path, "r") as f: ...
    
    1
    2
    3
    4
    5

# 1.3 深入理解文件模式 (mode)

模式由 “操作” + “类型” 组合而成。

  • 核心操作:
    • 'r': 只读 (Read)。文件必须存在,否则 FileNotFoundError。
    • 'w': 写入 (Write)。清空原有内容。文件不存在则创建。
    • 'a': 追加 (Append)。在末尾写入。文件不存在则创建。
  • 模式修改器:
    • '+': 更新。与 r/w/a 组合,变为读写模式。
    • 'b': 二进制 (Binary)。用于处理图片、音频等非文本文件。
    • 't': 文本 (Text)。默认模式,通常省略。
常见组合 描述
'r' 只读文本文件
'w' 覆盖写入文本文件
'a' 追加写入文本文件
'rb' 只读二进制文件
'wb' 覆盖写入二进制文件
'r+' 读写文本文件。指针在开头,写入会覆盖。
'a+' 读写文本文件。指针在末尾,写入是追加。若需读取,要先 seek(0)。

# 1.4 为何 encoding 至关重要?

计算机只认识 0 和 1。encoding 就是一本“密码本”,它定义了如何将人类的文字(如 '你')转换成计算机能存储的字节(如 b'\xe4\xbd\xa0'),以及如何反向转换。

  • 不指定 encoding 的风险: Python 会使用操作系统的默认编码,在 Windows(可能是 GBK)和 macOS/Linux(可能是 UTF-8)之间移动文件时,极易产生乱码。
  • 黄金法则: 处理文本文件时,永远显式指定 encoding='utf-8'。UTF-8 是全球通用的标准,能表示所有语言的字符。
# 正确的做法
with open("chinese_text.txt", "w", encoding="utf-8") as f:
    f.write("你好,世界!")

# 如果用错误的编码读取,会引发错误
try:
    with open("chinese_text.txt", "r", encoding="gbk") as f:
        print(f.read())
except UnicodeDecodeError as e:
    print(f"编码错误!{e}")
    # 输出: 编码错误!'gbk' codec can't decode byte 0xa0 in position 8: illegal multibyte sequence
1
2
3
4
5
6
7
8
9
10
11

# 2. with 语句 (上下文管理器)

with 语句是处理文件等需要“获取”和“释放”资源的最佳方式。它能确保无论代码块是正常结束还是中途发生错误,文件都能被自动、安全地关闭。

with 语句的原理: 它实际上是 try...finally 的一种简写。

# with 语句
with open("my_file.txt", "w") as f:
    f.write("Hello")

# 等价的 try...finally 结构
f = open("my_file.txt", "w")
try:
    f.write("Hello")
finally:
    f.close() # 无论 try 中是否出错,finally 块总会执行
1
2
3
4
5
6
7
8
9
10

显然,with 语句更简洁、更安全。


# 3. 写入文件:write() 与 writelines()

# 3.1 write(string): 写入单个字符串

此方法将一个字符串写入文件,并返回实际写入的字符数。

关键点:

  1. write() 不会自动添加换行符 \n。
  2. 文件缓冲区: 出于效率考虑,Python 在写入时可能先将数据放在内存缓冲区。数据只有在缓冲区满、文件关闭或手动调用 f.flush() 时,才保证被写入硬盘。
with open("log.txt", "w", encoding="utf-8") as f:
    f.write("Log started.\n")
    f.write("Processing data...")
    f.flush() # 强制将缓冲区内容写入磁盘
1
2
3
4

# 3.2 writelines(lines): 写入字符串列表

此方法接收一个字符串列表(或任何可迭代对象),并将其中每个字符串连续写入文件。

关键点: writelines() 也不会为每个字符串添加换行符。它仅仅是 for line in lines: f.write(line) 的一个高效替代。

lines_to_write = ["Event 1\n", "Event 2\n", "Event 3\n"]
with open("events.txt", "w", encoding="utf-8") as f:
    f.writelines(lines_to_write)
1
2
3

# 4. 读取文件:三种核心方法

准备一个用于读取的示例文件 poem.txt:

静夜思
李白
床前明月光,
疑是地上霜。
1
2
3
4

# 4.1 read(size=-1): 一次性读取

  • f.read(): 读取整个文件,返回一个字符串。读完后指针在文件末尾,再次调用返回空字符串 ''。
  • f.read(size): 读取指定 size 数量的字符。
  • 适用场景: 文件较小,或需要一次性处理全部内容时。对大文件要小心内存溢出。
with open("poem.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(f"再次读取: '{f.read()}'") # 输出: 再次读取: ''
1
2
3

# 4.2 readlines(): 所有行存入列表

  • f.readlines(): 读取所有行,返回一个列表,其中每个元素是文件的一行字符串。
  • 关键点: 每行末尾的换行符 \n 会被保留。
  • 适用场景: 文件不大,且需要对所有行进行索引、排序等列表操作时。
  • 处理换行符:
    with open("poem.txt", "r", encoding="utf-8") as f:
        lines_with_newline = f.readlines()
        stripped_lines = [line.strip() for line in lines_with_newline]
        print(stripped_lines) # 输出: ['静夜思', '李白', '床前明月光,', '疑是地上霜。']
    
    1
    2
    3
    4

# 4.3 readline() 与迭代:逐行处理 (最高效)

  • f.readline(): 每次只读取一行,返回一个字符串。读到文件末尾时返回空字符串 ''。
  • for line in f: 这是处理文本文件最推荐、最高效的方式。它逐行读取,内存占用小,代码简洁。
# 使用 readline() 和 while 循环的底层模拟
with open("poem.txt", "r", encoding="utf-8") as f:
    while True:
        line = f.readline()
        if not line: # 读到文件末尾,line 为 ''
            break
        print(line.strip())
1
2
3
4
5
6
7

# 5. 文件对象的属性

文件对象自身也包含一些有用的信息。

with open("poem.txt", "r+", encoding="utf-8") as f:
    print(f"文件名: {f.name}")         # poem.txt
    print(f"打开模式: {f.mode}")         # r+
    print(f"编码格式: {f.encoding}")   # utf-8
    print(f"是否可读? {f.readable()}") # True
    print(f"是否可写? {f.writable()}") # True
    print(f"文件是否关闭? {f.closed}") # False

print(f"\nwith 块结束后,文件是否关闭? {f.closed}") # True
1
2
3
4
5
6
7
8
9

# 6. 文件指针:seek() 与 tell()

可以把文件指针想象成文本编辑器里的光标,它标记了下一次读写操作的起始位置。

  • tell(): 返回指针当前位置的字节数。
  • seek(offset, whence=0): 移动指针。
    • offset: 偏移的字节数。
    • whence:
      • 0 (默认): 从文件头开始。
      • 1: 从当前位置开始。
      • 2: 从文件尾开始。
  • 重要: 在文本模式下,seek() 只保证 seek(0) 和 seek(offset, 0) 的可靠性。任意的 seek(offset, 1) 或 seek(offset, 2) 行为可能未定义。要进行精确的字节级移动,必须使用二进制模式 ('b')。
with open("poem.txt", "rb") as f: # 注意是二进制模式 'rb'
    print(f"指针在开头: {f.tell()}")    # 输出: 0
    data = f.read(6) # 一个汉字在UTF-8中占3字节,'静夜思\n' 占 3*3+1=10 字节
    print(f"读取6字节后: {f.tell()}")  # 输出: 6
    f.seek(0) # 移回文件开头
    print(f"seek(0)后: {f.tell()}")     # 输出: 0
1
2
3
4
5
6

# 7. 稳健编程:处理文件错误

直接操作文件很容易遇到问题,如文件不存在或没有权限。使用 try...except...finally 能让你的程序更健壮。

f = None # 在 try 外初始化,确保 finally 能访问
try:
    # with 语句可以写在 try 块内部
    with open("non_existent_file.txt", "r") as f:
        print(f.read())
except FileNotFoundError:
    print("错误:文件未找到!请检查文件名和路径。")
except PermissionError:
    print("错误:没有权限读取此文件。")
except Exception as e:
    print(f"发生了未知错误: {e}")
finally:
    if f and not f.closed:
        print("文件在 finally 块中被关闭。")
        f.close()
    else:
        print("程序结束。")

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 8. 文件系统管理:os 与 pathlib 模块

除了读写文件内容,我们还经常需要管理文件本身和它们所在的目录,例如创建、删除、移动、重命名等。Python 的 os 模块和 pathlib 模块为此提供了强大的支持。

# 8.1 传统方式:os 模块

os 模块是 Python 与操作系统交互的传统接口,功能非常全面。它主要包含两部分:直接的 os 函数(用于目录和文件操作)和 os.path 子模块(用于路径处理)。

# 路径处理 (os.path)

os.path 模块可以帮助你以跨平台的方式处理文件路径字符串。

import os

path_str = "/Users/alice/Documents/report.txt"

# 1. 路径拼接: os.path.join() - **极其重要**
# 自动使用适合操作系统的路径分隔符('/' 或 '\'),避免手动拼接错误
folder = "project"
filename = "main.py"
full_path = os.path.join(os.getcwd(), folder, filename)
print(f"安全拼接的路径: {full_path}")

# 2. 获取绝对路径: os.path.abspath()
relative_path = "my_script.py"
abs_path = os.path.abspath(relative_path)
print(f"绝对路径: {abs_path}")

# 3. 路径拆分
print(f"目录名: {os.path.dirname(path_str)}")   # /Users/alice/Documents
print(f"文件名: {os.path.basename(path_str)}")  # report.txt
print(f"目录和文件名元组: {os.path.split(path_str)}") # ('/Users/alice/Documents', 'report.txt')

# 4. 分离文件名和扩展名: os.path.splitext()
file_root, file_ext = os.path.splitext(path_str)
print(f"文件名部分: {file_root}") # /Users/alice/Documents/report
print(f"扩展名部分: {file_ext}")  # .txt

# 5. 检查路径
print(f"路径是否存在? {os.path.exists(path_str)}")
print(f"是否为文件? {os.path.isfile(path_str)}")
print(f"是否为目录? {os.path.isdir(os.path.dirname(path_str))}")

# 6. 获取文件大小 (字节)
# 先创建一个文件来获取大小
with open("temp_size_file.txt", "w") as f: f.write("12345")
print(f"文件大小: {os.path.getsize('temp_size_file.txt')} 字节")
os.remove("temp_size_file.txt") # 清理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 目录操作

# 1. 获取和切换当前工作目录
current_dir = os.getcwd()
print(f"当前工作目录: {current_dir}")
# os.chdir('/target/directory') # 可以切换到其他目录

# 2. 创建目录
# os.mkdir('single_folder') # 只能创建单层目录,如果已存在会报错
os.makedirs('level1/level2', exist_ok=True) # 推荐!可以递归创建多层目录,exist_ok=True 表示如果已存在则不报错

# 3. 列出目录内容
print(f"当前目录内容: {os.listdir('.')}") # '.' 表示当前目录

# 4. 删除目录
os.rmdir('level1/level2') # 只能删除空目录
os.rmdir('level1')
# os.removedirs('path') # 会递归删除路径中所有的空目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 文件操作

# 1. 重命名文件
with open("old.txt", "w") as f: f.write("data")
os.rename("old.txt", "new.txt")

# 2. 移动文件 (rename 的妙用)
os.makedirs("storage", exist_ok=True)
os.rename("new.txt", os.path.join("storage", "moved.txt")) # 当目标路径在不同目录时,rename 实现移动效果

# 3. 删除文件
os.remove(os.path.join("storage", "moved.txt"))
os.rmdir("storage")
1
2
3
4
5
6
7
8
9
10
11

# 8.2 现代方式:pathlib 模块 (推荐)

pathlib 在 Python 3.4+ 中引入,提供了一个面向对象的接口来处理文件系统路径,代码更直观、易读、不易出错。

from pathlib import Path

# 创建 Path 对象
p = Path("/Users/alice/Documents/report.txt")

# 1. 路径拼接 (使用 / 运算符)
project_dir = Path.cwd() # 获取当前工作目录,等同于 os.getcwd()
new_path = project_dir / "data" / "config.json"
print(f"Pathlib 拼接路径: {new_path}")

# 2. 获取路径的各个部分 (作为属性访问)
print(f"父目录: {p.parent}")    # /Users/alice/Documents
print(f"文件名: {p.name}")      # report.txt
print(f"文件名词干: {p.stem}")    # report
print(f"文件后缀: {p.suffix}")    # .txt

# 3. 检查路径
print(f"路径是否存在? {new_path.exists()}")
print(f"是否为文件? {p.is_file()}")
print(f"是否为目录? {p.is_dir()}")

# 4. 直接打开文件
# with p.open('r', encoding='utf-8') as f: ...

# 5. 创建和删除目录
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
# data_dir.rmdir() # 只能删除空目录

# 6. 重命名和移动
# report_path = Path('report.txt')
# report_path.touch() # 创建空文件
# report_path.rename('new_report.txt')
# report_path.rename(data_dir / 'moved_report.txt')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 8.3 综合案例:自动整理下载文件夹

假设你的下载文件夹里乱七八糟,有各种文件。我们来写一个脚本,按文件类型(后缀名)自动将它们归类到不同的子文件夹中。

# 版本 A: 使用 os 模块实现

import os
import shutil # 使用 shutil.move 进行移动更稳健

# 设定源文件夹和目标文件夹
SOURCE_DIR = os.getcwd() # 假设脚本就在下载文件夹里运行
DEST_DIR = os.path.join(SOURCE_DIR, "Organized_Files")
os.makedirs(DEST_DIR, exist_ok=True)

# 遍历源文件夹中的所有条目
for filename in os.listdir(SOURCE_DIR):
    source_path = os.path.join(SOURCE_DIR, filename)
    
    # 只处理文件,跳过目录和脚本自身
    if os.path.isdir(source_path) or filename.endswith(".py"):
        continue

    # 获取文件后缀
    _, file_ext = os.path.splitext(filename)
    file_ext = file_ext[1:].lower() if file_ext else "no_extension" # 去掉点,转小写

    # 创建目标子文件夹
    dest_folder_path = os.path.join(DEST_DIR, file_ext)
    os.makedirs(dest_folder_path, exist_ok=True)

    # 移动文件
    dest_path = os.path.join(dest_folder_path, filename)
    print(f"正在移动: {filename} -> {dest_folder_path}")
    shutil.move(source_path, dest_path)

print("文件整理完毕!")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 版本 B: 使用 pathlib 模块实现 (更简洁)

from pathlib import Path
import shutil

SOURCE_DIR = Path.cwd()
DEST_DIR = SOURCE_DIR / "Organized_Files"
DEST_DIR.mkdir(exist_ok=True)

# Path.iterdir() 返回一个生成器,效率更高
for path_object in SOURCE_DIR.iterdir():
    # 只处理文件,跳过目录和脚本自身
    if path_object.is_dir() or path_object.name.endswith(".py"):
        continue
    
    # 获取文件后缀
    file_ext = path_object.suffix[1:].lower() if path_object.suffix else "no_extension"

    # 创建目标子文件夹
    dest_folder_path = DEST_DIR / file_ext
    dest_folder_path.mkdir(exist_ok=True)

    # 移动文件
    dest_path = dest_folder_path / path_object.name
    print(f"正在移动: {path_object.name} -> {dest_folder_path}")
    shutil.move(str(path_object), str(dest_path)) # shutil.move 接受字符串路径

print("文件整理完毕!")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 9. 综合案例:统计日志中的 IP 地址

这个案例将串联起文件的读取、字符串处理、字典统计和结果写入等多个核心知识点。

任务:读取一个日志文件 access.log,统计其中每个 IP 地址的访问次数,按访问次数从高到低排序,并将格式化后的报告写入 ip_counts_sorted.txt。

# 1. 准备日志文件
log_data = """192.168.1.1 - - [10/Mar/2023] "GET /home"
203.0.113.45 - - [10/Mar/2023] "GET /about"
192.168.1.1 - - [10/Mar/2023] "POST /login"
192.168.1.2 - - [10/Mar/2023] "GET /home"
203.0.113.45 - - [10/Mar/2023] "GET /products"
"""
with open("access.log", "w", encoding="utf-8") as f:
    f.write(log_data)

# 2. 分析日志并统计
ip_counts = {}
try:
    with open("access.log", "r", encoding="utf-8") as f:
        for line in f:
            if not line.strip(): continue # 跳过空行
            ip = line.split(" ")[0]
            ip_counts[ip] = ip_counts.get(ip, 0) + 1 # 使用 .get() 更简洁
except FileNotFoundError:
    print("日志文件未找到!")
    ip_counts = {} # 确保 ip_counts 是一个空字典

# 3. 排序统计结果
# sorted() 返回一个列表,元素是 (ip, count) 元组
# key=lambda item: item[1] 表示按元组的第二个元素(即 count)排序
# reverse=True 表示降序
sorted_ips = sorted(ip_counts.items(), key=lambda item: item[1], reverse=True)

# 4. 将结果写入报告文件
with open("ip_counts_sorted.txt", "w", encoding="utf-8") as report_file:
    report_file.write("IP 访问统计报告 (按次数降序)\n")
    report_file.write("="*30 + "\n")
    for ip, count in sorted_ips:
        report_file.write(f"{ip:<20} | 次数: {count}\n") # 左对齐,增加格式美感

print("排序后的报告生成完毕!")
# ip_counts_sorted.txt 内容:
# IP 访问统计报告 (按次数降序)
# ==============================
# 192.168.1.1          | 次数: 2
# 203.0.113.45         | 次数: 2
# 192.168.1.2          | 次数: 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
编辑此页 (opens new window)
上次更新: 2025/07/23, 06:33:16
生成式
面向对象

← 生成式 面向对象→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式