首页 > 编程语言 >C++入门教程:第八篇 - 文件I/O操作

C++入门教程:第八篇 - 文件I/O操作

时间:2024-09-11 19:49:08浏览次数:12  
标签:文件 outputFile 第八篇 入门教程 C++ cpp include open inputFile

C++入门教程:第八篇 - 文件I/O操作

文件I/O(输入/输出)是程序与外部存储设备进行数据交换的关键操作。在C++中,文件I/O操作由标准库提供的流类完成。通过这些流类,程序可以读写文件,处理文件内容。本文将介绍C++中的文件I/O基础,包括如何打开、读写和关闭文件。

1. 文件流基础

C++提供了几种文件流类,用于处理不同类型的文件操作。主要的文件流类包括ifstream(输入文件流)、ofstream(输出文件流)和fstream(文件流)。ifstream用于从文件中读取数据,ofstream用于向文件写入数据,而fstream则支持读写操作。

1.1 打开文件

在进行文件操作之前,必须打开文件。文件流类提供了构造函数和open方法来打开文件。

1.1.1 使用构造函数打开文件

以下示例展示了如何使用ifstreamofstream的构造函数来打开文件:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    // 打开输入文件
    ifstream inputFile("input.txt");

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    // 打开输出文件
    ofstream outputFile("output.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    // 关闭文件
    inputFile.close();
    outputFile.close();

    return 0;
}

cpp

1.1.2 使用open方法打开文件

你还可以使用open方法来打开文件:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ifstream inputFile;
    inputFile.open("input.txt");

    if (!inputFile) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    ofstream outputFile;
    outputFile.open("output.txt");

    if (!outputFile) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    // 关闭文件
    inputFile.close();
    outputFile.close();

    return 0;
}

cpp

2. 读取文件

从文件中读取数据可以使用ifstream类。C++标准库提供了多种方法来读取文件内容,如按行读取、按字符读取等。

2.1 按行读取文件

使用getline函数可以按行读取文件内容,并存储到一个string对象中。


cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main() {
    ifstream inputFile("input.txt");

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    string line;
    while (getline(inputFile, line)) {
        cout << line << endl;
    }

    inputFile.close();
    return 0;
}

cpp

2.2 按字符读取文件

使用流提取运算符>>可以按字符读取文件内容:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ifstream inputFile("input.txt");

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    char ch;
    while (inputFile.get(ch)) {
        cout << ch;
    }

    inputFile.close();
    return 0;
}

cpp

2.3 读取文件到数组

将文件内容读取到一个数组或容器中,适用于处理较小的文件:


cpp

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

int main() {
    ifstream inputFile("input.txt");

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    vector<string> lines;
    string line;
    while (getline(inputFile, line)) {
        lines.push_back(line);
    }

    for (const auto& l : lines) {
        cout << l << endl;
    }

    inputFile.close();
    return 0;
}

cpp

3. 写入文件

向文件中写入数据可以使用ofstream类。C++标准库提供了多种方法来写入数据,包括按行写入、按字符写入等。

3.1 按行写入文件

使用<<运算符可以将数据写入文件中:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream outputFile("output.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    outputFile << "Hello, World!" << endl;
    outputFile << "This is a line of text." << endl;

    outputFile.close();
    return 0;
}

cpp

3.2 按字符写入文件

使用put方法可以按字符写入文件:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream outputFile("output.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    outputFile.put('H');
    outputFile.put('e');
    outputFile.put('l');
    outputFile.put('l');
    outputFile.put('o');

    outputFile.close();
    return 0;
}

cpp

3.3 写入格式化数据

使用<<运算符可以将格式化的数据写入文件:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream outputFile("output.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    int age = 30;
    double salary = 55000.75;

    outputFile << "Age: " << age << endl;
    outputFile << "Salary: " << salary << endl;

    outputFile.close();
    return 0;
}

cpp

4. 文件流的状态检查

在进行文件操作时,检查文件流的状态非常重要,以确保操作成功进行。常见的文件流状态包括goodfaileofbad状态。

4.1 检查文件流状态

使用good()fail()eof()bad()方法可以检查文件流的状态:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ifstream inputFile("input.txt");

    if (inputFile.good()) {
        cout << "File opened successfully" << endl;
    } else if (inputFile.fail()) {
        cerr << "File opening failed" << endl;
    } else if (inputFile.eof()) {
        cerr << "End of file reached" << endl;
    } else if (inputFile.bad()) {
        cerr << "File stream is in a bad state" << endl;
    }

    inputFile.close();
    return 0;
}

cpp

4.2 清除文件流的错误状态

在捕获和处理文件流错误后,可以使用clear()方法重置文件流的状态:


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ifstream inputFile("input.txt");

    if (!inputFile) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    // 读取文件内容
    // ...

    // 清除错误状态
    inputFile.clear();
    inputFile.close();
    return 0;
}

cpp

5. 文件操作的最佳实践

在进行文件I/O操作时,遵循一些最佳实践可以提高程序的健壮性和性能。

5.1 确保文件正常关闭

在完成文件操作后,务必关闭文件,以确保文件资源被正确释放。


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream outputFile("output.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    // 写入文件内容
    outputFile << "Some text" << endl;

    // 关闭文件
    outputFile.close();

    return 0;
}

cpp

5.2 使用RAII管理文件流

RAII(Resource Acquisition Is Initialization)是一种编程惯例,确保资源在对象的生命周期内被正确管理。在C++中,RAII是通过构造函数和析构函数来实现资源的自动管理,确保在对象销毁时释放资源。在文件处理的上下文中,这意味着我们可以利用fstream类来自动管理文件资源。

5.2.1 基本示例

fstream类(包括ifstreamofstream)使用RAII来自动管理文件的打开和关闭。以下是一个简单的例子,展示了如何使用ifstream类读取文件,并依靠RAII机制来确保文件流在完成后自动关闭。


cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main() {
    // 使用RAII管理文件流
    ifstream inputFile("example.txt");

    // 检查文件是否成功打开
    if (!inputFile.is_open()) {
        cerr << "Error: Could not open file for reading" << endl;
        return 1;
    }

    string line;
    while (getline(inputFile, line)) {
        // 逐行读取文件内容并输出
        cout << line << endl;
    }

    // 文件流将在此自动关闭(RAII机制)
    return 0;
}

cpp

在这个示例中,ifstream对象inputFile在构造时打开文件,并在inputFile对象离开作用域时自动调用其析构函数,从而关闭文件流。

5.2.2 自定义类实现RAII

我们也可以定义一个自定义类来管理文件流,进一步演示RAII的应用。这对于需要自定义文件处理行为的情况尤其有用。


cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class FileHandler {
private:
    fstream fileStream;

public:
    // 构造函数打开文件
    FileHandler(const string& fileName, ios::openmode mode) {
        fileStream.open(fileName, mode);
        if (!fileStream.is_open()) {
            cerr << "Error: Could not open file" << endl;
            throw runtime_error("File opening failed");
        }
    }

    // 析构函数自动关闭文件
    ~FileHandler() {
        if (fileStream.is_open()) {
            fileStream.close();
        }
    }

    // 提供访问文件流的接口
    fstream& getStream() {
        return fileStream;
    }
};

int main() {
    try {
        FileHandler fileHandler("example.txt", ios::in);
        string line;

        while (getline(fileHandler.getStream(), line)) {
            // 逐行读取文件内容并输出
            cout << line << endl;
        }

        // 文件流将在此自动关闭(RAII机制)
    } catch (const runtime_error& e) {
        cerr << e.what() << endl;
        return 1;
    }

    return 0;
}

cpp

在这个示例中,FileHandler类封装了fstream对象,并通过构造函数打开文件。析构函数确保文件在对象销毁时被正确关闭。使用FileHandler类可以简化文件处理并减少错误。

5.2.3 RAII与异常安全

RAII还帮助我们处理异常情况。由于资源的管理与对象的生命周期绑定,当异常发生时,资源会被自动释放,从而保证程序的异常安全。


cpp

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class SafeFileHandler {
private:
    fstream fileStream;

public:
    SafeFileHandler(const string& fileName, ios::openmode mode) {
        fileStream.open(fileName, mode);
        if (!fileStream.is_open()) {
            throw runtime_error("Failed to open file");
        }
    }

    ~SafeFileHandler() {
        if (fileStream.is_open()) {
            fileStream.close();
        }
    }

    fstream& getStream() {
        return fileStream;
    }
};

int main() {
    try {
        SafeFileHandler fileHandler("example.txt", ios::in);
        string line;

        while (getline(fileHandler.getStream(), line)) {
            // 逐行读取文件内容并输出
            cout << line << endl;
        }
    } catch (const runtime_error& e) {
        cerr << "Error: " << e.what() << endl;
        return 1;
    }

    return 0;
}

cpp

6. 文件的附加操作

在C++中,除了基本的读写操作外,还有一些附加操作可以帮助你更好地管理文件和数据。

6.1 追加写入数据

有时你可能希望向一个已存在的文件中追加数据,而不是覆盖文件内容。可以使用ofstreamopen方法并传递ios::app模式来实现追加操作。


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream outputFile;
    outputFile.open("output.txt", ios::app);

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    outputFile << "Appending this line to the file." << endl;

    outputFile.close();
    return 0;
}

cpp

6.2 读取文件的当前位置

在读取文件时,可能需要知道当前读取的位置。这可以通过tellg方法获取。


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ifstream inputFile("input.txt");

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    // 读取部分数据
    string line;
    getline(inputFile, line);

    // 获取当前读取位置
    streampos pos = inputFile.tellg();
    cout << "Current position: " << pos << endl;

    inputFile.close();
    return 0;
}

cpp

6.3 设置文件的读写位置

你可以使用seekgseekp方法来设置文件的读写位置。


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    // 写入文件
    ofstream outputFile("example.txt");
    outputFile << "Hello, World!";
    outputFile.close();

    // 读取文件
    ifstream inputFile("example.txt");

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    // 移动到文件的开始位置
    inputFile.seekg(0);

    // 读取文件内容
    string content;
    getline(inputFile, content);
    cout << "Content: " << content << endl;

    inputFile.close();
    return 0;
}

cpp

7. 二进制文件处理

除了文本文件,C++也支持对二进制文件的操作。二进制文件用于存储非文本数据,如图像、音频或自定义数据格式。处理二进制文件时,需要注意读取和写入数据的方式。

7.1 写入二进制数据

使用ofstreambinary模式可以写入二进制数据。


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream outputFile("binary.dat", ios::binary);

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    int num = 12345;
    outputFile.write(reinterpret_cast<const char*>(&num), sizeof(num));

    outputFile.close();
    return 0;
}

cpp

7.2 读取二进制数据

读取二进制数据的方式与写入类似,但使用ifstreambinary模式。


cpp

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ifstream inputFile("binary.dat", ios::binary);

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    int num;
    inputFile.read(reinterpret_cast<char*>(&num), sizeof(num));
    cout << "Read number: " << num << endl;

    inputFile.close();
    return 0;
}

cpp

7.3 处理自定义二进制格式

在处理自定义二进制格式时,你需要定义数据结构并确保读写操作与数据结构一致。例如,定义一个自定义结构体并将其写入和读取到二进制文件中。


cpp

#include <iostream>
#include <fstream>

using namespace std;

struct Person {
    char name[50];
    int age;
};

int main() {
    // 写入自定义数据结构
    ofstream outputFile("person.dat", ios::binary);

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return 1;
    }

    Person person = {"John Doe", 30};
    outputFile.write(reinterpret_cast<const char*>(&person), sizeof(person));

    outputFile.close();

    // 读取自定义数据结构
    ifstream inputFile("person.dat", ios::binary);

    if (!inputFile.is_open()) {
        cerr << "Error: Could not open input file" << endl;
        return 1;
    }

    Person readPerson;
    inputFile.read(reinterpret_cast<char*>(&readPerson), sizeof(readPerson));
    cout << "Name: " << readPerson.name << ", Age: " << readPerson.age << endl;

    inputFile.close();
    return 0;
}

cpp

8. 文件的同步和异步操作

文件操作通常是同步的,即操作会阻塞直到完成。然而,在处理大文件或需要高性能时,可以使用异步操作来避免阻塞主线程。

8.1 同步文件操作

同步文件操作是默认的文件操作方式,在文件操作完成前,程序会等待。


cpp

#include <iostream>
#include <fstream>
#include <thread>

using namespace std;

void writeFile() {
    ofstream outputFile("sync.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return;
    }

    outputFile << "This is a synchronous write operation." << endl;

    outputFile.close();
}

int main() {
    writeFile();
    cout << "File written synchronously." << endl;
    return 0;
}

cpp

8.2 异步文件操作

异步文件操作可以使用线程来实现,将文件操作放在一个独立的线程中,以避免主线程阻塞。


cpp

#include <iostream>
#include <fstream>
#include <thread>

using namespace std;

void writeFileAsync() {
    ofstream outputFile("async.txt");

    if (!outputFile.is_open()) {
        cerr << "Error: Could not open output file" << endl;
        return;
    }

    outputFile << "This is an asynchronous write operation." << endl;

    outputFile.close();
}

int main() {
    thread t(writeFileAsync);
    t.join(); // 等待线程完成
    cout << "File written asynchronously." << endl;
    return 0;
}

cpp

9. 总结

本文详细介绍了C++中关于文件I/O操作的各个方面,包括文件的基本读写操作、附加操作、二进制文件处理以及同步与异步文件操作。掌握这些技能可以帮助你更有效地进行文件管理和数据处理。在下一篇教程中,我们将探讨C++中的多线程编程,学习如何使用线程来实现并发操作,提高程序的性能和响应能力。

 

标签:文件,outputFile,第八篇,入门教程,C++,cpp,include,open,inputFile
From: https://blog.csdn.net/HYP_Coder/article/details/142148633

相关文章

  • C++ 虚析构函数简单测试
    classBase{public:virtual~Base(){cout<<"~Base"<<'\n';}};classDerived:publicBase{public:~Derived(){cout<<"~Derived"<<'\n';}};intmain(){{......
  • 【C++】vector常见用法
    ......
  • C++:类与对象——详解多态原理、虚函数和抽象类
    1.多态基本内容C++中的多态是面向对象编程的一个重要特性,指的是同一个函数或对象在不同的情况下可以表现出不同的行为。多态通常通过继承和虚函数来实现。它分为两种类型:编译时多态(静态多态)和运行时多态(动态多态)。多态分为两类:静态多态:函数重载和运算符重载属于静态......
  • 南沙C++信奥老师解一本通题: 1315:【例4.5】集合的划分
    ​ 【题目描述】【输入】给出n和k。【输出】n个元素a1,a2,……,an放入k个无标号盒子中去的划分数S(n,k)。【输入样例】106 【输出样例】22827 #include<iostream>usingnamespacestd;longlongSplit(intn,intplate)//等同于n个不同的数......
  • C++模拟实现stack和queue(容器适配器)
    适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。简单理解,将模板参数给成容器,就是容器适配器,写成参数的容器的各种接口,均满足需要。#include<list>#includ......
  • 走进C++——初识与探索
    一.C++发展历史  C++的起源可以追溯到1979年,当时BjarneStroustrup(本贾尼·斯特劳斯特卢普)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语⾔)在表达能⼒、可维护性和可扩展性......
  • 22级五年制C语言入门教程-(5)格式化输入输出
    1.输入和输出在程序的使用中,我们经常可以看的这么一个场景:用户需要输入数据,经过程序运算,得到结果后输出。在C语言中,输入数据和输出数据都是由库函数完成的,通过语句来输入/输出。2.格式化输出—printf()函数C语言程序运算的结果在内存中,我们需要将其输出到指定设备中,我们才可以......
  • 22级五年制C语言入门教程-(6)运算符
    1.运算符概述运算符是一种编译器执行特定的数学或逻辑操作的符号。C语言提供了以下类型的运算符:算术运算符关系运算符逻辑运算符位运算符赋值运算符条件运算符其他运算符2.算术运算符算术运算符分为单目运算符和双目运算符,单目运算符表示只需要一个操作数,双目运算符需......
  • C++ 类继承
    一、继承1.继承的概念和意义继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,产生新的类,称子类。例如下面的Student类和Teacher类,它们都有人名,性别,电话,年龄,住址等信息。不同的是Student类有学号之分,而老师有职称之......
  • 中国电科网安校园招聘:C++工程师
      本文介绍2024届秋招中,中国电子科技网络信息安全有限公司的C/C++开发工程师岗位一面的面试基本情况、提问问题等。  2024年10月投递了中国电子科技网络信息安全有限公司的C/C++开发工程师岗位,并不清楚所在的部门。目前完成了一面,在这里记录一下一面经历。  这一次面试面......