C++文件流式编程的优势

文件操作是很多程序都会用到的功能,在c语言中,常常使用FILE*指针和一系列标准库函数(如fopenfclosefreadfwritefprintffscanf)进行文件操作,看看一段c语言的文件操作代码

#include <stdio.h>FILE* fp = fopen("data.txt", "r");if (fp == NULL) { perror("打开失败"); return -1; }int num;while (fscanf(fp, "%d", &num) != EOF) {  // 需手动检查返回值    printf("读取到: %d\n", num);}fclose(fp);  // 必须手动关闭,否则泄漏资源

c语言作为一个面向过程的语言,上面的操作就充分体现了这个特点,通过函数打开——读取/写入——关闭的一系列过程,完成对文件的操作。而且格式化写入的过程中,要靠人工保证匹配正确性, 一旦格式不匹配时就会导致运行时错误

下面来看看C++是怎么做的

#include <iostream>#include <fstream>  // C++文件流头文件int main() {    std::ofstream outFile("example.txt");  // 创建输出文件流(写入模式)    if (!outFile) {  // 检查文件是否成功打开        std::cerr << "文件打开失败!" << std::endl;        return 1;    }    outFile << "Hello, C++!" << std::endl;  // 使用 << 操作符写入数据    outFile.close();  // 关闭文件(析构时也会自动关闭)    return 0;}

是不是很眼熟?写文件跟打印输出的写法很类似,把要写的内容输出到文件对象就可以了,非常直观,也不用考虑格式匹配的问题。这就是c++的面对对象的实现方式带来的优势

从函数调用到对象交互

C++文件操作的革命性变化在于将文件操作封装为流对象,通过<<(插入)和>>(提取)运算符实现类型安全的读写。文件操作最常用的三个类是:

  • ifstream

    :文件输入对象(读操作)

  • ofstream

    :文件输出对象(写操作)

  • fstream

    :文件输入输出对象(读写操作)

对文件操作时,就根据具体的操作创建不同的类对象,创建对象时指定文件就相当于打开了文件,然后对文件对象进行流操作就可以了,看看具体的例子

#include <iostream>#include <fstream>#include <string>
using namespace std;
int main() {    // 写入文件    ofstream outFile("test_cpp.txt");  //创建即打开文件    if (!outFile.is_open()) {  //判断是否正常打开        cerr << "无法打开文件进行写入" << endl;        return 1;    }
    outFile << "Hello, C++ File!" << endl;    outFile << "这是第二行内容" << endl;    outFile.close(); // 可以省略,析构函数会自动关闭
    // 读取文件    ifstream inFile("test_cpp.txt");    if (!inFile) { // 等价于!inFile.is_open()        cerr << "无法打开文件进行读取" << endl;        return 1;    }
    string line;    cout << "文件内容:" << endl;    while (getline(inFile, line)) { // 逐行读取        cout << line << endl;    }
    // 检查是否正常读取结束    if (inFile.eof()) {        cout << "读取完成" << endl;    } else if (inFile.fail()) {        cerr << "读取过程中发生错误" << endl;    }
    return 0;}

除了使用流操作符>>,<<外,也可以使用read,write方法对文件进行读写,特别是对二进制文件的读写

#include <iostream>#include <fstream>
int main() {    int num = 42;    double pi = 3.14159;
    // 写入二进制文件    std::ofstream binOut("data.bin", std::ios::binary);        binOut.write(reinterpret_cast<const char*>(&num), sizeof(num)); //写入num    binOut.write(reinterpret_cast<const char*>(&pi), sizeof(pi)); //写入pi    binOut.close();
    // 读取二进制文件    std::ifstream binIn("data.bin", std::ios::binary);    int readNum;    double readPi;
    //读取一个int数据到readnum    binIn.read(reinterpret_cast<char*>(&readNum), sizeof(readNum));        //读取一个double数据到readPi    binIn.read(reinterpret_cast<char*>(&readPi), sizeof(readPi));    binIn.close();
    std::cout << "读取的数字: " << readNum << ", Pi: " << readPi << std::endl;    return 0;}

RAII机制保障资源安全释放

RAII机制(资源获取即初始化)是C++流安全的基石:流对象在析构时自动调用close(),无论函数正常返回还是异常退出,都能确保资源释放。对比C语言中需要在每个return前调用fclose的繁琐,C++实现了"一次声明,全程无忧"的资源管理。如下面代码

#include <fstream>using namespace std;int main() {    ifstream in("data.txt");  // 构造即打开文件,RAII自动管理    int num;
    // 流对象在布尔上下文自动转换为!fail(),简洁判断读取状态    while (in >> num) {  // 类型安全:若num类型不匹配,编译报错        cout << "读取到: " << num << endl;    }    // 无需手动close,in析构时自动释放资源    return 0;}

当然,也可以使用close方法手动关闭文件流

错误处理:流状态标志

C++流对象内置状态标志,可通过good()/fail()/eof()精准判断错误类型:

ifstream in("data.txt");if (!in) {    if (in.eof()) cerr << "已到文件尾";    else if (in.fail()) cerr << "格式错误";    else if (in.bad()) cerr << "致命错误";}

对比C语言需要组合feof/ferror的繁琐判断,C++流状态管理更清晰高效。

二进制文件随机存取

c++文件流对象也支持对文件随机存取,而且定义了输入和输出两个文件指针,分别用seekg和seekp方法来获取。另外还有提供了指示文件位置的几个常量

ios_base::beg    文件开始处,相当于SEEK_SET

ios_bae::cur    当前文件指针位置,相当于SEEK_CUR

ios_base::end  文件结尾处,相当于SEEK_END

具体例子

#include <iostream>#include <fstream>#include <string>
using namespace std;
struct Student {    int id;    char name[20];    float score;};
int main() {    // 二进制写入    ofstream outFile("students.dat", ios::binary);    if (!outFile) {        cerr << "无法打开文件进行写入" << endl;        return 1;    }
    Student s1 = {1, "张三", 90.5};    Student s2 = {2, "李四", 85.0};
    outFile.write(reinterpret_cast<const char*>(&s1), sizeof(s1));    outFile.write(reinterpret_cast<const char*>(&s2), sizeof(s2));    outFile.close();
    // 二进制读取和随机访问    ifstream inFile("students.dat", ios::binary);    if (!inFile) {        cerr << "无法打开文件进行读取" << endl;        return 1;    }
    // 移动到第二个学生的位置    inFile.seekg(sizeof(Student), ios::beg);
    Student s;    inFile.read(reinterpret_cast<char*>(&s), sizeof(s));
    cout << "学号: " << s.id << endl;    cout << "姓名: " << s.name << endl;    cout << "成绩: " << s.score << endl;
    // 获取文件大小    inFile.seekg(0, ios::end);   //移动到文件结尾    streampos fileSize = inFile.tellg();  //获取文件指针当前位置    cout << "文件大小: " << fileSize << " 字节" << endl;    cout << "学生数量: " << fileSize / sizeof(Student) << endl;
    return 0;}

顺便提一下,随机访问一般只对二进制文件使用,因为文本文件可能由于文件编码和换行符的影响导致文件指针偏移量计算出现误差,从而出错

最后做个c和c++文件操作的简单对比

对比项

C语言(stdio.h

C++(<fstream>流)

文件操作方式

FILE*+ 函数(fopenfprintf

流类(ofstreamifstream

语法

函数式(fprintf

流式(<<和 >>

错误处理

返回值(如NULL

fail()eof()bad()

资源管理

手动fclose

RAII(自动关闭)

二进制支持

fread/fwrite

write/read(需std::ios::binary

易用性

较低(函数多)

更高(流操作直观)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宋康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值