← 返回 Day 16 正文

Day 16 · 图解

文件 I/O 图解


1. 文件打开模式体系图

graph TB subgraph "打开模式体系" direction TB MODE[open(file, mode)] MODE --> BASIC[基本操作] MODE --> TYPE[文件类型] MODE --> EXTRA[附加操作] BASIC --> R["r - 只读"] BASIC --> W["w - 写入(清空)"] BASIC --> A["a - 追加"] BASIC --> X["x - 排他创建"] TYPE --> T["t - 文本模式(默认)"] TYPE --> B["b - 二进制模式"] EXTRA --> PLUS["+ - 读写"] end subgraph "常见组合" COM1["r+t"] --> |"文本读写<br>常用: JSON编辑"| COM1U COM2["w+b"] --> |"二进制读写<br>常用: 图片处理"| COM2U COM3["a+t"] --> |"追加读取<br>常用: 日志查看"| COM3U COM4["x+t"] --> |"排他写<br>常用: 避免覆盖"| COM4U end
graph TB
    subgraph "打开模式体系"
        direction TB
        MODE[open(file, mode)]
        MODE --> BASIC[基本操作]
        MODE --> TYPE[文件类型]
        MODE --> EXTRA[附加操作]
        
        BASIC --> R["r - 只读"]
        BASIC --> W["w - 写入(清空)"]
        BASIC --> A["a - 追加"]
        BASIC --> X["x - 排他创建"]
        
        TYPE --> T["t - 文本模式(默认)"]
        TYPE --> B["b - 二进制模式"]
        
        EXTRA --> PLUS["+ - 读写"]
    end
    
    subgraph "常见组合"
        COM1["r+t"] --> |"文本读写<br>常用: JSON编辑"| COM1U
        COM2["w+b"] --> |"二进制读写<br>常用: 图片处理"| COM2U
        COM3["a+t"] --> |"追加读取<br>常用: 日志查看"| COM3U
        COM4["x+t"] --> |"排他写<br>常用: 避免覆盖"| COM4U
    end

2. with 语句执行流程

sequenceDiagram participant User as 代码块 participant With as with 语句 participant Enter as __enter__ participant Body as 文件操作 participant Exit as __exit__ participant File as 文件 User->>With: with open("file", "r") as f: With->>Enter: 调用 f.__enter__() Enter->>File: 打开文件 Enter-->>With: 返回文件对象 f Note over With,Body: 进入缩进块 Body->>File: 读写操作 Note over Body: 读写正常 或 发生异常 Body->>Exit: 离开缩进块 Exit->>File: f.close() alt 无异常 Exit-->>With: 返回 None With-->>User: 继续执行 else 有异常 Exit-->>With: 返回 True → 吞异常<br>返回 False → 抛异常 With-->>User: 处理异常 end
sequenceDiagram
    participant User as 代码块
    participant With as with 语句
    participant Enter as __enter__
    participant Body as 文件操作
    participant Exit as __exit__
    participant File as 文件
    
    User->>With: with open("file", "r") as f:
    With->>Enter: 调用 f.__enter__()
    Enter->>File: 打开文件
    Enter-->>With: 返回文件对象 f
    Note over With,Body: 进入缩进块
    Body->>File: 读写操作
    Note over Body: 读写正常 或 发生异常
    Body->>Exit: 离开缩进块
    Exit->>File: f.close()
    
    alt 无异常
        Exit-->>With: 返回 None
        With-->>User: 继续执行
    else 有异常
        Exit-->>With: 返回 True → 吞异常<br>返回 False → 抛异常
        With-->>User: 处理异常
    end

3. 文本模式 vs 二进制模式处理流程

flowchart LR subgraph "文本模式 (t)" direction TB A1["字符串 str<br>'Hello'"] -->|"encode()<br>UTF-8"| A2["字节流<br>b'Hello'"] A2 -->|"write()"| A3["文件系统"] A3 -->|"read()"| A4["字节流<br>b'Hello'"] A4 -->|"decode()<br>UTF-8"| A5["字符串 str<br>'Hello'"] end subgraph "二进制模式 (b)" direction TB B1["字节串 bytes<br>b'Hello'"] -->|"write()"| B2["文件系统"] B2 -->|"read()"| B3["字节串 bytes<br>b'Hello'"] end A3 -.->|"\\n ↔ \\r\\n<br>平台转换"| A3_PLATFORM
flowchart LR
    subgraph "文本模式 (t)"
        direction TB
        A1["字符串 str<br>'Hello'"] -->|"encode()<br>UTF-8"| A2["字节流<br>b'Hello'"]
        A2 -->|"write()"| A3["文件系统"]
        A3 -->|"read()"| A4["字节流<br>b'Hello'"]
        A4 -->|"decode()<br>UTF-8"| A5["字符串 str<br>'Hello'"]
    end
    
    subgraph "二进制模式 (b)"
        direction TB
        B1["字节串 bytes<br>b'Hello'"] -->|"write()"| B2["文件系统"]
        B2 -->|"read()"| B3["字节串 bytes<br>b'Hello'"]
    end
    
    A3 -.->|"\\n ↔ \\r\\n<br>平台转换"| A3_PLATFORM

4. 文件指针 seek/tell 示意图

文件内容:  H e l l o   W o r l d  \n
          0 1 2 3 4 5 6 7 8 9 10 11
          
① open() 后:
  H e l l o   W o r l d  \n
  ↑
  pos=0 (文件开头)

② f.read(5) 后:
  H e l l o   W o r l d  \n
            ↑
            pos=5

③ f.read() 后 (读完):
  H e l l o   W o r l d  \n
                              ↑
                              pos=12 (文件末尾)

④ f.seek(6): 移动到第 6 个位置
  H e l l o   W o r l d  \n
              ↑
              pos=6

⑤ f.seek(-3, 2): 从末尾往前 3
  H e l l o   W o r l d  \n
                          ↑
                          pos=9

5. 不同打开模式的文件指针位置

┌────────────────────────────────────────────┐
│                   文件内容                    │
│  ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐  │
│  │H│e│l│l│o│ │W│o│r│l│d│ │!│\n│T│e│s│t│  │
│  └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘  │
│  pos:  0       5       10        15         │
└────────────────────────────────────────────┘

模式 r/r+:    ↑ (pos=0)         只读或读写
模式 w/w+:    清空 → ↑ (pos=0)  先清空再写
模式 a/a+:                     ↑ (pos=18) 追加到末尾
模式 x:       新文件 → ↑ (pos=0) 不存在才创建

6. 编码错误处理策略对比

flowchart TD ENC[读取文件] --> CHECK{编码匹配?} CHECK -->|"✅ 是"| OK[正常读取] CHECK -->|"❌ 否"| ERR[编码错误] ERR --> STRATEGY{处理策略} STRATEGY -->|"strict (默认)"| RAISE["抛出 UnicodeDecodeError<br>最安全,不丢失数据"] STRATEGY -->|"ignore"| IGNORE["静默跳过非法字节<br>⚠️ 可能丢失数据"] STRATEGY -->|"replace"| REPLACE["用 ? 替换<br>保留内容长度"] STRATEGY -->|"backslashreplace"| BS["用 \\xNN 转义<br>不丢失信息"] STRATEGY -->|"surrogateescape"| SE["Python 专用编码<br>用于 OS 接口"]
flowchart TD
    ENC[读取文件] --> CHECK{编码匹配?}
    CHECK -->|"✅ 是"| OK[正常读取]
    CHECK -->|"❌ 否"| ERR[编码错误]
    
    ERR --> STRATEGY{处理策略}
    
    STRATEGY -->|"strict (默认)"| RAISE["抛出 UnicodeDecodeError<br>最安全,不丢失数据"]
    STRATEGY -->|"ignore"| IGNORE["静默跳过非法字节<br>⚠️ 可能丢失数据"]
    STRATEGY -->|"replace"| REPLACE["用 ? 替换<br>保留内容长度"]
    STRATEGY -->|"backslashreplace"| BS["用 \\xNN 转义<br>不丢失信息"]
    STRATEGY -->|"surrogateescape"| SE["Python 专用编码<br>用于 OS 接口"]

7. 文件操作 API 速查图

classDiagram class FileObject { +name: str +mode: str +encoding: str +closed: bool +read(n) str +readline() str +readlines() list +write(s) int +writelines(lines) +seek(offset, whence) int +tell() int +truncate(size) +flush() +close() +fileno() int +seekable() bool +readable() bool +writable() bool +detach() IOBase } class TextIOWrapper { +encoding: str +errors: str +newlines: str 文本模式包装器 } class BufferedRandom { 可读写的缓冲流 } FileObject <|-- TextIOWrapper FileObject <|-- BufferedRandom
classDiagram
    class FileObject {
        +name: str
        +mode: str
        +encoding: str
        +closed: bool
        +read(n) str
        +readline() str
        +readlines() list
        +write(s) int
        +writelines(lines)
        +seek(offset, whence) int
        +tell() int
        +truncate(size)
        +flush()
        +close()
        +fileno() int
        +seekable() bool
        +readable() bool
        +writable() bool
        +detach() IOBase
    }
    
    class TextIOWrapper {
        +encoding: str
        +errors: str
        +newlines: str
        文本模式包装器
    }
    
    class BufferedRandom {
        可读写的缓冲流
    }
    
    FileObject <|-- TextIOWrapper
    FileObject <|-- BufferedRandom

8. 大文件处理策略对比

flowchart LR subgraph "小文件 (<100MB)" A["f.read()"] -->|"一次性加载<br>速度最快"| A_RES["✅ 简单直接"] end subgraph "大文本文件" B["for line in f"] -->|"逐行迭代<br>内存高效"| B_RES["✅ 逐行处理"] end subgraph "超大二进制文件" C["while chunk = f.read(8KB)"] -->|"分块读取<br>可控内存"| C_RES["✅ 流式处理"] end FILE_SIZE{文件大小} --> A FILE_SIZE --> B FILE_SIZE --> C
flowchart LR
    subgraph "小文件 (<100MB)"
        A["f.read()"] -->|"一次性加载<br>速度最快"| A_RES["✅ 简单直接"]
    end
    
    subgraph "大文本文件"
        B["for line in f"] -->|"逐行迭代<br>内存高效"| B_RES["✅ 逐行处理"]
    end
    
    subgraph "超大二进制文件"
        C["while chunk = f.read(8KB)"] -->|"分块读取<br>可控内存"| C_RES["✅ 流式处理"]
    end
    
    FILE_SIZE{文件大小} --> A
    FILE_SIZE --> B
    FILE_SIZE --> C