C++ fstream标准输入/出流
C++ fstream标准输入/出流
一、fstream标准输入/输出流
核心功能与特性
- 文件读取:支持从文本文件或二进制文件中读取数据,可按字符、行、格式化数据(如整数、浮点数)等方式读取。
- 自动资源管理:对象析构时会自动关闭关联的文件,避免手动管理文件句柄的繁琐和遗漏。
- 模式支持:默认以文本模式打开文件,也可显式指定为二进制模式(
std::ios::binary),用于读取二进制数据(如图片、自定义格式文件)。
二、ifstream 标准输入流
ifstream(输入文件流)常用函数及用法
函数 / 操作 说明 示例代码 open()打开文件,支持指定路径和打开模式(如 ios::in(输入模式)、ios::binary(二进制模式)等)`ifstream file; file.open("data.txt", ios::in ios::binary);` is_open()检查文件是否成功打开,返回 bool值if (!file.is_open()) { cerr << "文件打开失败" << endl; }close()关闭文件,释放资源(对象析构时自动关闭,手动关闭更严谨) file.close();getline()读取一行文本到 std::string对象string line; while (getline(file, line)) { cout << line << endl; }>>运算符格式化读取(如整数、浮点数、字符串等结构化数据) int num; double val; file >> num >> val;read()二进制读取,将指定字节数的数据读入字符数组 char buf[100]; file.read(buf, 50); // 读取50字节到bufeof()检查是否到达文件末尾,返回 bool值while (!file.eof()) { /* 执行读取操作 */ }fail()检查是否发生读取错误(如格式不匹配、读取越界等) if (file.fail()) { cerr << "读取失败" << endl; }seekg()设置读取指针位置(支持 ios::beg(文件开头)、ios::cur(当前位置)、ios::end(文件末尾)偏移)file.seekg(20, ios::beg); // 从文件开头偏移20字节tellg()获取当前读取指针的位置(返回字节数) streampos pos = file.tellg(); cout << "当前读取位置:" << pos << endl;#include <iostream> #include <fstream> // 包含ifstream #include <string> int main() { // 1. 创建ifstream对象,打开文件(若文件不存在,is_open()会返回false) std::ifstream inFile("input.txt"); // 文件名可替换为实际路径(如"../data.txt") // 2. 检查文件是否成功打开 if (!inFile.is_open()) { std::cerr << "错误:无法打开文件 input.txt!" << std::endl; return 1; // 打开失败,退出程序 } // 3. 逐行读取文件内容(使用getline) std::string line; // 存储每行内容 std::cout << "文件内容如下:" << std::endl; while (std::getline(inFile, line)) { // 读取一行到line,直到文件末尾 std::cout << line << std::endl; // 输出当前行 } // 4. 检查读取过程中是否发生错误(非文件末尾的错误) if (inFile.fail() && !inFile.eof()) { std::cerr << "错误:读取文件时发生异常!" << std::endl; } // 5. 关闭文件(对象析构时会自动关闭,手动关闭更规范) inFile.close(); return 0; }
三、标准输出流
ofstream(输出文件流)常用函数及用法
函数 / 操作 说明 示例代码 open()打开文件,支持模式有 ios::out(默认,覆盖文件)、ios::app(追加模式)、ios::binary(二进制模式)等`ofstream file; file.open("log.txt", ios::out ios::app);` is_open()检查文件是否成功打开,返回 bool值if (!file.is_open()) { cerr << "文件打开失败" << endl; }close()关闭文件,释放资源 file.close();<<运算符格式化写入(如字符串、整数、浮点数等结构化数据) file << "ID: " << 1001 << ", Score: " << 95.5;write()二进制写入,将字符数组的指定字节数写入文件 char buf[] = "binary data"; file.write(buf, sizeof(buf));seekp()设置写入指针位置 file.seekp(10, ios::beg); // 从文件开头偏移10字节开始写入tellp()获取当前写入指针的位置(返回字节数) streampos pos = file.tellp(); cout << "当前写入位置:" << pos << endl;flush()强制刷新输出缓冲区,立即将数据写入文件(避免缓冲区未满时数据丢失) file.flush();#include <iostream> #include <fstream> // 包含ofstream #include <string> int main() { // 1. 创建ofstream对象,打开文件(默认模式为ios::out,会覆盖原有内容;若要追加,用ios::app) std::ofstream outFile("output.txt"); // 文件名可替换为实际路径 // 2. 检查文件是否成功打开 if (!outFile.is_open()) { std::cerr << "错误:无法创建/打开文件 output.txt!" << std::endl; return 1; } // 3. 向文件写入内容(使用<<运算符,类似cout) outFile << "这是第一行文本" << std::endl; // 写入字符串并换行 outFile << "第二行:包含一个数字 " << 123 << std::endl; // 混合写入字符串和整数 outFile << "第三行:浮点数 " << 3.14159 << std::endl; // 写入浮点数 // 4. 强制刷新缓冲区(立即将数据写入文件,避免程序崩溃时数据丢失) outFile.flush(); // 5. 关闭文件 outFile.close(); std::cout << "内容已成功写入 output.txt!" << std::endl; return 0; }
四、实战案例
struct Point { int id; double x; double y; double z; // ==重载 bool operator==(const Point &p) { if(this->x == p.x && this->y == p.y && this->z == p.z) { return true; } return false; } }; std::vector<Point> readPointsFromCSV(const std::string& filename) { std::vector<Point> points; std::ifstream file(filename); if (file.is_open()) { std::string line; // 跳过标题行 std::getline(file, line); std::getline(file, line); while (std::getline(file, line)) { // 遇到空行则终止循环 if (line.empty()) { break; } std::stringstream ss(line); std::string id_str, x_str, y_str, z_str; std::getline(ss, id_str, ','); std::getline(ss, x_str, ','); std::getline(ss, y_str, ','); std::getline(ss, z_str, ','); Point p; p.id = std::stoi(id_str); p.x = std::stod(x_str); p.y = std::stod(y_str); p.z = std::stod(z_str); points.push_back(p); } file.close(); } return points; } std::vector<Segment> readSegmentsFromCSV(const std::string& filename) { //变关系顺序表 std::vector<Segment> segments; //标准输入流 打开文件 std::ifstream file(filename); bool isPointsSection = true; if (file.is_open()) { std::string line; while (std::getline(file, line)) { if (line.find("# Segments section") != std::string::npos) { isPointsSection = false; // 跳过标题行 std::getline(file, line); continue; } if (!isPointsSection) { std::stringstream ss(line); std::string id_str, startId_str, endId_str; std::getline(ss, id_str, ','); std::getline(ss, startId_str, ','); std::getline(ss, endId_str, ','); Segment s; s.id = std::stoi(id_str); s.startPointId = std::stoi(startId_str); s.endPointId = std::stoi(endId_str); segments.push_back(s); } } file.close(); } return segments; }这段代码的核心功能是将一个字符串按逗号分隔成多个子串,通常用于解析 CSV 格式的单行数据(如从文件中读取的一行点坐标数据)。以下是逐行解释:
1.
std::stringstream ss(line);
std::stringstream是 C++ 标准库中的字符串流类(需包含<sstream>头文件),可以像操作输入流(如cin)一样操作字符串。- 这行代码创建了一个
stringstream对象ss,并将字符串line的内容传入ss中。此后,ss就可以像 “内存中的输入流” 一样,从中读取数据。2.
std::string id_str, x_str, y_str, z_str;
- 定义了 4 个字符串变量,用于存储从
line中分割出的子串(通常对应 CSV 中的列值,如点的 ID、X 坐标、Y 坐标、Z 坐标)。3.
std::getline(ss, 变量名, ',');
std::getline是用于从流中读取字符串的函数,这里的用法是按指定分隔符(逗号,)分割字符串流ss中的内容。函数参数说明:
getline(输入流, 接收结果的字符串, 分隔符),作用是从输入流中读取字符,直到遇到分隔符(或流结束),将读取到的内容存入接收字符串中(分隔符本身不会被存入)。
第一次:
std::getline(ss, id_str, ',')从
ss中读取字符,直到遇到第一个逗号,,将内容存入id_str(例如,若line是"0,-0.098,4.79,0.0",则id_str会是"0")。第二次:
std::getline(ss, x_str, ',')从第一个逗号后的位置继续读取,直到遇到第二个逗号,内容存入
x_str(上例中会得到"-0.098")。第三次:
std::getline(ss, y_str, ',')继续读取,直到第三个逗号,内容存入
y_str(上例中会得到"4.79")。第四次:
std::getline(ss, z_str, ',')继续读取,直到第四个逗号(或流结束),内容存入
z_str(上例中会得到"0.0")。整体作用
假设
line是 CSV 文件中的一行点数据(如"3,0.479,-4.873,0.000"),这段代码会将其按逗号分割,最终:
id_str = "3"(点 ID 的字符串形式)x_str = "0.479"(X 坐标的字符串形式)y_str = "-4.873"(Y 坐标的字符串形式)z_str = "0.000"(Z 坐标的字符串形式)后续通常会通过
std::stoi(转整数)、std::stod(转浮点数)将这些字符串转换为对应的数据类型,存入结构体(如Point)中。注意点
- 若
line中的逗号数量少于 3 个(如只有 2 个逗号),则后面的变量会接收剩余所有内容(例如z_str可能为空或包含多余字符),需注意后续转换时的错误处理。- 若
line中没有逗号,id_str会接收整个line,其余变量为空。
