Ch 6: 文件与 I/O 操作
- 掌握文件读写操作
- 理解路径处理
- 处理二进制文件
- 使用流缓冲区
6.1 Python 文件读写
Section titled “6.1 Python 文件读写”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" - 二进制写6.2 C++ 文件流
Section titled “6.2 C++ 文件流”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;RAII 方式(推荐)
Section titled “RAII 方式(推荐)”#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; // 空格分隔读取6.3 pathlib vs std::filesystem
Section titled “6.3 pathlib vs std::filesystem”Python pathlib
Section titled “Python pathlib”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)C++ std::filesystem
Section titled “C++ std::filesystem”#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)) { // ...}6.4 二进制文件
Section titled “6.4 二进制文件”Python 二进制
Section titled “Python 二进制”# 读二进制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 structpacked = struct.pack("iId", 42, 3.14, b'x') # int, doubleunpacked = struct.unpack("iId", packed)
# numpy 二进制import numpy as nparr = np.array([1, 2, 3])arr.tofile("array.bin")loaded = np.fromfile("array.bin", dtype=np.int32)C++ 二进制
Section titled “C++ 二进制”#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));6.5 流缓冲区
Section titled “6.5 流缓冲区”Python 文件对象缓冲区
Section titled “Python 文件对象缓冲区”# 自动缓冲with open("file.txt", "w", buffering=8192) as f: f.write("hello") # 可能不立即写入磁盘
# 刷新f.flush() # 刷新缓冲区f.seek(0) # 改变位置f.tell() # 当前文件位置
# 文本模式行缓冲import syssys.stdout.write("prompt: ") # 自动 flushC++ 流缓冲区
Section titled “C++ 流缓冲区”#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();6.6 字符串流
Section titled “6.6 字符串流”Python StringIO
Section titled “Python StringIO”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()C++ stringstream
Section titled “C++ stringstream”#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();6.7 格式化 I/O
Section titled “6.7 格式化 I/O”Python
Section titled “Python”# 字符串格式化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 日期与时间。