云计算百科
云计算领域专业知识百科平台

C#转Python第4.3篇:文件读写:with 语句 vs using:几乎一模一样的设计哲学!

在 C# 里读文件,using (var reader = new StreamReader("file.txt")) 一行搞定,离开 using 块自动 Dispose,不会泄漏文件句柄。

在 Python 里读文件,with open("file.txt") as f: 一行搞定,离开 with 块自动关闭文件,也不会泄漏文件句柄。

当我第一次在 Python 里用 with open() 的时候,我的内心是:"这不就是 C# 的 using 吗?连设计哲学都一样!"

后来我才明白,Python 的 with 语句就是参考了 C# 的 using——两者都是"离开作用域自动清理资源"的语法糖。唯一的区别是,C# 的 using 基于 IDisposable 接口,Python 的 with 基于上下文管理器协议(__enter__ 和 __exit__)。

Python 的 with 语句和 C# 的 using 简直是异父异母的亲兄弟——设计哲学几乎一模一样。

基础语法对比

C# 版本:

// 读取全部内容
string content = File.ReadAllText("file.txt");

// 逐行读取
foreach (string line in File.ReadLines("file.txt"))
{
    Console.WriteLine(line);
}

// 写入文件
File.WriteAllText("output.txt", "Hello, World!");

// 使用 StreamReader
using (var reader = new StreamReader("file.txt"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}

Python 版本:

# 读取全部内容
with open("file.txt") as f:
    content = f.read()

# 逐行读取
with open("file.txt") as f:
    for line in f:
        print(line)

# 写入文件
with open("output.txt", "w") as f:
    f.write("Hello, World!")

# 使用 readline
with open("file.txt") as f:
    line = f.readline()
    while line:
        print(line)
        line = f.readline()

对比一下:

操作C#Python
读全部 File.ReadAllText() open().read()
读一行 reader.ReadLine() f.readline()
写入 File.WriteAllText() open().write()
资源管理 using with
自动关闭 Dispose() __exit__()

设计哲学几乎一样——用语法糖保证资源清理。

文件打开模式

C# 的文件模式:

// 读取(默认)
var reader = new StreamReader("file.txt");

// 写入(覆盖)
var writer = new StreamWriter("file.txt");

// 追加
var writer = new StreamWriter("file.txt", append: true);

// 创建/覆盖(File 类)
File.WriteAllText("file.txt", content);
File.AppendAllText("file.txt", content);

Python 的文件模式:

# 读取(默认)
f = open("file.txt", "r")

# 写入(覆盖)
f = open("file.txt", "w")

# 追加
f = open("file.txt", "a")

# 读写
f = open("file.txt", "r+")

# 二进制读取
f = open("image.png", "rb")

# 二进制写入
f = open("output.bin", "wb")

Python 的模式更灵活:

模式说明
r 读取(默认)
w 写入(覆盖)
a 追加
r+ 读写
rb 二进制读取
wb 二进制写入
x 创建(文件已存在则报错)

C# 没有 x 模式,你得自己判断文件是否存在。

编码处理

C# 的编码:

// UTF-8(默认)
string content = File.ReadAllText("file.txt");

// 指定编码
string content = File.ReadAllText("file.txt", Encoding.UTF8);
string content = File.ReadAllText("file.txt", Encoding.GetEncoding("GBK"));

Python 的编码:

# UTF-8(默认,Python 3)
with open("file.txt", encoding="utf-8") as f:
    content = f.read()

# 指定编码
with open("file.txt", encoding="gbk") as f:
    content = f.read()

Python 3 默认 UTF-8,Python 2 默认 ASCII(这是 Python 2 的经典坑)。

上下文管理器:with 语句

Python 的 with 语句可以同时管理多个资源:

with open("input.txt") as fin, open("output.txt", "w") as fout:
    for line in fin:
        fout.write(line)

C# 也可以嵌套 using:

using (var reader = new StreamReader("input.txt"))
using (var writer = new StreamWriter("output.txt"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        writer.WriteLine(line);
    }
}

效果一样,都是"两个资源都自动清理"。

自定义上下文管理器

Python 可以自定义上下文管理器,这是 C# 的 IDisposable 做不到的灵活:

class Timer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        self.elapsed = time.time() – self.start
        print(f"耗时: {self.elapsed:.2f} 秒")
        return False

with Timer():
    # 你的代码
    import time
    time.sleep(1)
# 输出: 耗时: 1.00 秒

C# 要实现类似功能得写一个 IDisposable 类:

class Timer : IDisposable
{
    private Stopwatch _stopwatch = new Stopwatch();

    public void Dispose()
    {
        _stopwatch.Stop();
        Console.WriteLine($"耗时: {_stopwatch.Elapsed.TotalSeconds:F2} 秒");
    }
}

using (new Timer())
{
    Thread.Sleep(1000);
}

Python 的 with 更灵活——你可以在 __exit__ 里做任何清理工作,包括抑制异常(返回 True)。

文件遍历:逐行 vs 逐块

C# 逐行遍历:

foreach (string line in File.ReadLines("file.txt"))
{
    Console.WriteLine(line);
}

Python 逐行遍历:

with open("file.txt") as f:
    for line in f:
        print(line)

Python 的文件对象本身就是迭代器,可以直接 for line in f,比 C# 更简洁。

Python 逐块读取(处理大文件):

with open("large_file.txt") as f:
    while chunk := f.read(8192):
        process(chunk)

C# 逐块读取:

using (var reader = new StreamReader("large_file.txt"))
{
    char[] buffer = new char[8192];
    int charsRead;
    while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        Process(new string(buffer, 0, charsRead));
    }
}

临时文件

Python 有 tempfile 模块,自动管理临时文件生命周期:

import tempfile

# 自动删除的临时文件
with tempfile.NamedTemporaryFile(delete=True) as tmp:
    tmp.write(b"Hello, World!")
    tmp.flush()
    process_file(tmp.name)
# 文件自动删除

C# 也有 Path.GetTempFileName(),但需要手动删除:

string tempFile = Path.GetTempFileName();
try
{
    File.WriteAllText(tempFile, "Hello, World!");
    ProcessFile(tempFile);
}
finally
{
    File.Delete(tempFile);
}

Python 的 with 让临时文件管理更优雅。

迁移指南:C# 开发者最容易犯的错

  • 忘记指定编码:Python 3 默认 UTF-8,但处理旧文件时可能需要指定 GBK

  • **忘记用 with**:和 C# 忘记 using 一样,会导致资源泄漏

  • 文件模式搞错:w 会覆盖文件,a 才是追加

  • 二进制模式搞错:读图片、音频等必须用 rb/wb

  • 路径处理:Python 用 /,Windows 用 \\,建议用 pathlib

  • 坑点提醒

    文件没有关闭——不用 with 的后果:

    f = open("file.txt")
    content = f.read()
    # 忘记 f.close(),文件句柄泄漏

    编码错误——处理非 UTF-8 文件:

    with open("gbk_file.txt") as f:
        content = f.read()  # UnicodeDecodeError

    解决方案:

    with open("gbk_file.txt", encoding="gbk", errors="ignore") as f:
        content = f.read()

    路径问题——Windows 和 Linux 路径不同:

    # 不推荐
    path = "data/files/file.txt"

    # 推荐
    from pathlib import Path
    path = Path("data") / "files" / "file.txt"

    真实案例:我有个同事从 C# 转 Python,写了一个日志处理脚本。脚本每天处理几个 GB 的日志文件,但他用 f.read() 一次性读取,结果内存爆了。后来改成逐行读取 for line in f: 才解决问题。Python 的文件对象是惰性加载的,for line in f 不会一次性把整个文件读入内存。

    pathlib:Python 的路径神器

    Python 3.4+ 引入的 pathlib,比字符串拼接路径更优雅:

    from pathlib import Path

    # 创建路径
    p = Path("data") / "files" / "file.txt"

    # 读取文件
    content = p.read_text()

    # 写入文件
    p.write_text("Hello, World!")

    # 遍历目录
    for f in Path(".").glob("*.py"):
        print(f)

    # 递归遍历
    for f in Path(".").rglob("*.py"):
        print(f)

    C# 也有 Path.Combine() 和 Directory.GetFiles(),但没有 pathlib 这么面向对象。

    一句话总结

    C# 的 using 和 Python 的 with 是同一个设计哲学的两种实现——"离开作用域自动清理资源",两种语言在这个问题上达成了惊人的一致。

    下一篇咱们来聊聊 JSON 处理——C# 的 System.Text.Json vs Python 的 json 模块,两种语言的"数据序列化哲学"又有啥不同。


    📦 示例代码:C# 转 Python 全系列配套练习代码(含 48 章示例)

    • GitHub:GitHub – LadyKiller1025/csharp-python-demos: C# vs Python 学习系列 – Demo 代码合集 · GitHub

    • Gitee:https://gitee.com/qakjhzx/csharp-python-demos

    💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » C#转Python第4.3篇:文件读写:with 语句 vs using:几乎一模一样的设计哲学!
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!