在 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()
对比一下:
| 读全部 | 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
💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!
网硕互联帮助中心




评论前必须登录!
注册