Skip to content

Ch 6: 文件与 I/O 操作

  • 掌握文件读写操作
  • 理解路径处理
  • 处理二进制文件
  • 使用流缓冲区

Python 的文件操作简洁直观:

# 读文件
with open("file.txt", "r") as f:
content = f.read() # 读取全部
lines = f.readlines() # 读取所有行
line = f.readline() # 读取一行
# 逐行迭代
with open("file.txt", "r") as f:
for line in f: # 文件对象可迭代
print(line.strip())
# 写文件
with open("file.txt", "w") as f:
f.write("hello\n")
f.writelines(["line1\n", "line2\n"])
# 追加
with open("file.txt", "a") as f:
f.write("append\n")
# 模式
# "r" - 读(默认)
# "w" - 写(覆盖)
# "a" - 追加
# "x" - 创建(不存在则创建)
# "rb" - 二进制读
# "wb" - 二进制写

C++ 使用流进行文件操作:

#include <fstream>
#include <sstream>
// 读文件
std::ifstream file("file.txt");
if (file.is_open()) {
// 读取全部
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
// 逐行读取
std::string line;
while (std::getline(file, line)) {
std::cout << line << std::endl;
}
file.close();
}
// 写文件
std::ofstream out("file.txt");
out << "hello" << std::endl;
out.close();
// 追加
std::ofstream append("file.txt", std::ios::app);
append << "append" << std::endl;
#include <fstream>
// RAII - 文件在构造时打开,析构时自动关闭
void read_file() {
std::ifstream file("file.txt");
if (!file) {
std::cerr << "Cannot open file" << std::endl;
return;
}
std::string line;
while (std::getline(file, line)) {
std::cout << line << std::endl;
}
} // file 自动关闭
std::ifstream file("file.txt");
// 检查是否打开成功
if (!file) {
std::cerr << "Failed to open file" << std::endl;
}
// 检查流状态
file >> std::ws; // 跳过空白
if (file.eof()) { // 是否到达文件末尾
std::cout << "End of file" << std::endl;
}
// 格式化读取
int num;
double val;
std::string word;
file >> num >> val >> word; // 空格分隔读取
from pathlib import Path
p = Path("project")
# 存在性检查
p.exists()
p.is_file()
p.is_dir()
# 路径组件
p.parent # 父目录
p.name # 文件名(不含路径)
p.stem # 不含扩展名的文件名
p.suffix # 扩展名(.txt)
p.suffixes # 所有扩展名(Unix)
# 构造路径
Path("dir") / "subdir" / "file.txt"
Path.home() / "Documents"
Path.cwd()
# 文件操作
p.mkdir(parents=True, exist_ok=True) # 创建目录
p.rmdir() # 删除空目录
p.unlink() # 删除文件
p.rename("new_name.txt") # 重命名
p.replace("new_path.txt") # 移动/替换
# 遍历
for f in p.glob("*.txt"):
print(f.name)
for f in p.rglob("**/*.txt"): # 递归
print(f.name)
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
fs::path p = "project";
// 存在性检查
bool exists = fs::exists(p);
bool is_file = fs::is_regular_file(p);
bool is_dir = fs::is_directory(p);
// 路径组件
fs::path parent = p.parent_path();
fs::path name = p.filename();
fs::path stem = p.stem();
fs::path ext = p.extension();
// 构造路径
fs::path full_path = "dir" / "subdir" / "file.txt";
full_path = fs::current_path() / "file.txt";
full_path = fs::path("/home/user") / "Documents";
// 文件操作
fs::create_directories(p); // 创建目录(递归)
fs::remove(p); // 删除文件或空目录
fs::rename("old.txt", "new.txt"); // 重命名/移动
// 遍历
for (const auto& entry : fs::directory_iterator(p)) {
if (entry.is_regular_file() && entry.path().extension() == ".txt") {
std::cout << entry.path().filename() << std::endl;
}
}
// 递归遍历(C++17)
for (const auto& entry : fs::recursive_directory_iterator(p)) {
if (entry.is_regular_file()) {
std::cout << entry.path() << std::endl;
}
}
// glob(C++20)
for (const auto& entry : fs::directory_iterator(p,
fs::directory_options::skip_permission_denied)) {
// ...
}
# 读二进制
with open("data.bin", "rb") as f:
data = f.read()
# 写二进制
with open("data.bin", "wb") as f:
f.write(b"\x00\x01\x02\x03")
# 结构化二进制(struct)
import struct
packed = struct.pack("iId", 42, 3.14, b'x') # int, double
unpacked = struct.unpack("iId", packed)
# numpy 二进制
import numpy as np
arr = np.array([1, 2, 3])
arr.tofile("array.bin")
loaded = np.fromfile("array.bin", dtype=np.int32)
#include <fstream>
#include <vector>
// 读二进制
std::ifstream file("data.bin", std::ios::binary);
std::vector<char> buffer;
if (file) {
file.seekg(0, std::ios::end); // 移到末尾
std::streamsize size = file.tellg(); // 获取大小
file.seekg(0, std::ios::beg); // 回到开头
buffer.resize(size);
file.read(buffer.data(), size);
}
// 写二进制
std::ofstream out("data.bin", std::ios::binary);
int num = 42;
double val = 3.14;
out.write(reinterpret_cast<const char*>(&num), sizeof(num));
out.write(reinterpret_cast<const char*>(&val), sizeof(val));
// 读取
out.close();
std::ifstream in("data.bin", std::ios::binary);
in.read(reinterpret_cast<char*>(&num), sizeof(num));
in.read(reinterpret_cast<char*>(&val), sizeof(val));
# 自动缓冲
with open("file.txt", "w", buffering=8192) as f:
f.write("hello") # 可能不立即写入磁盘
# 刷新
f.flush() # 刷新缓冲区
f.seek(0) # 改变位置
f.tell() # 当前文件位置
# 文本模式行缓冲
import sys
sys.stdout.write("prompt: ") # 自动 flush
#include <fstream>
std::ofstream file("file.txt");
// 获取底层缓冲区
std::streambuf* buf = file.rdbuf();
// 直接操作缓冲区
buf->sputn("hello", 5); // 写入
buf->sgetn(buf, 5); // 读取
// 刷新
file.flush(); // 刷新缓冲区
file.sync(); // 同步到磁盘
// 位置
file.seekp(0); // 写位置
file.tellp(); // 当前写位置
file.seekg(0); // 读位置
file.tellg(); // 当前读位置
// stringstream - 内存中的流
#include <sstream>
std::ostringstream oss;
oss << "value: " << 42;
std::string s = oss.str();
from io import StringIO, BytesIO
# 文本流
sio = StringIO()
sio.write("hello")
sio.write("world")
print(sio.getvalue())
# 解析
sio = StringIO("1 2 3")
a, b, c = sio.read().split()
# BytesIO - 二进制
bio = BytesIO()
bio.write(b"\x00\x01\x02")
data = bio.getvalue()
#include <sstream>
// 输出流
std::ostringstream oss;
oss << "value: " << 42;
std::string s = oss.str();
// 输入流
std::istringstream iss(s);
std::string word;
int num;
iss >> word >> num; // word="value:", num=42
// 格式化
oss.str(""); // 清空
oss.clear(); // 清除错误状态
oss << std::fixed << std::setprecision(4) << 3.14159;
std::string formatted = oss.str();
# 字符串格式化
print(f"{42:05d}") # "00042"
print(f"{3.14159:.4f}") # "3.1416"
print(f"{'hello':>10}") # " hello"
# 文件格式化写
with open("data.txt", "w") as f:
for i in range(10):
f.write(f"{i:5d} {i*i:10d}\n")
#include <iomanip>
// 格式化输出
std::cout << std::setw(5) << std::setfill('0') << 42 << std::endl;
std::cout << std::fixed << std::setprecision(4) << 3.14159 << std::endl;
std::cout << std::right << std::setw(10) << "hello" << std::endl;
// 文件格式化写
#include <fstream>
std::ofstream out("data.txt");
for (int i = 0; i < 10; ++i) {
out << std::setw(5) << i
<< std::setw(10) << i * i
<< std::endl;
}
  • std::ifstream/std::ofstream 是 C++ 文件操作方式
  • std::filesystem 处理路径操作,类似 Python 的 pathlib
  • RAII 自动管理文件句柄
  • 二进制文件需要 std::ios::binary
  • std::stringstream 用于内存中的字符串操作

下章预告:ch07 日期与时间。