在 C++ 中执行文件操作

C++C++Beginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,你将学习如何在 C++ 中执行各种文件操作。实验内容包括打开文件进行读取和写入、将文本数据写入文件、从文本文件中读取数据、检查文件打开状态、处理文件读写错误、处理二进制文件、定位文件指针以及关闭文件以释放资源。你将通过使用 C++ 标准库中的基本文件流类 ofstreamifstream 来与文件进行交互,获得实践经验。通过本实验,你将对 C++ 编程中的文件处理有扎实的理解。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL cpp(("`C++`")) -.-> cpp/BasicsGroup(["`Basics`"]) cpp(("`C++`")) -.-> cpp/ControlFlowGroup(["`Control Flow`"]) cpp(("`C++`")) -.-> cpp/AdvancedConceptsGroup(["`Advanced Concepts`"]) cpp(("`C++`")) -.-> cpp/IOandFileHandlingGroup(["`I/O and File Handling`"]) cpp(("`C++`")) -.-> cpp/StandardLibraryGroup(["`Standard Library`"]) cpp/BasicsGroup -.-> cpp/strings("`Strings`") cpp/ControlFlowGroup -.-> cpp/if_else("`If...Else`") cpp/AdvancedConceptsGroup -.-> cpp/pointers("`Pointers`") cpp/AdvancedConceptsGroup -.-> cpp/structures("`Structures`") cpp/AdvancedConceptsGroup -.-> cpp/exceptions("`Exceptions`") cpp/IOandFileHandlingGroup -.-> cpp/output("`Output`") cpp/IOandFileHandlingGroup -.-> cpp/files("`Files`") cpp/StandardLibraryGroup -.-> cpp/string_manipulation("`String Manipulation`") subgraph Lab Skills cpp/strings -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/if_else -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/pointers -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/structures -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/exceptions -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/output -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/files -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} cpp/string_manipulation -.-> lab-446086{{"`在 C++ 中执行文件操作`"}} end

使用 ofstream 和 ifstream 打开文件

在本步骤中,你将学习如何使用 C++ 中的两个基本文件流类来打开文件:ofstream 用于写入文件,ifstream 用于读取文件。这些类是 C++ 标准库的一部分,提供了基本的文件处理功能。

首先,在 WebIDE 终端中导航到项目目录:

cd ~/project

创建一个名为 file_operations.cpp 的 C++ 文件:

touch file_operations.cpp

将以下代码添加到 file_operations.cpp 文件中:

#include <iostream>
#include <fstream>  // 包含文件流头文件

int main() {
    // 使用 ofstream 打开文件以进行写入
    std::ofstream outputFile("example.txt");

    // 检查文件是否成功打开
    if (outputFile.is_open()) {
        std::cout << "文件成功打开以进行写入!" << std::endl;
        outputFile.close();  // 关闭文件
    } else {
        std::cout << "无法打开文件以进行写入。" << std::endl;
    }

    // 使用 ifstream 打开文件以进行读取
    std::ifstream inputFile("example.txt");

    // 检查文件是否成功打开
    if (inputFile.is_open()) {
        std::cout << "文件成功打开以进行读取!" << std::endl;
        inputFile.close();  // 关闭文件
    } else {
        std::cout << "无法打开文件以进行读取。" << std::endl;
    }

    return 0;
}

让我们分解关键概念:

  1. #include <fstream>:包含文件流库
  2. std::ofstream:用于写入文件的输出文件流
  3. std::ifstream:用于读取文件的输入文件流
  4. is_open():检查文件是否成功打开
  5. close():在操作完成后关闭文件

编译程序:

g++ file_operations.cpp -o file_operations

运行可执行文件:

./file_operations

示例输出:

文件成功打开以进行写入!
文件成功打开以进行读取!

关于文件流的一些重要注意事项:

  • 在执行操作之前,始终检查文件是否成功打开
  • 使用完文件后记得关闭文件
  • ofstream 用于写入文件
  • ifstream 用于读取文件
  • 这两个类都属于 <fstream> 头文件

你可以将文件流类比为打开和关闭文件的门。ofstream 允许你向房间内写入内容,而 ifstream 则允许你读取房间内的内容。

将文本数据写入文件

在本步骤中,你将学习如何使用 C++ 中的 ofstream 类将文本数据写入文件。基于上一步的内容,你将探索如何将字符串、数字和多行内容写入文件。

创建一个名为 write_files.cpp 的 C++ 文件:

touch ~/project/write_files.cpp

将以下代码添加到 write_files.cpp 文件中:

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

int main() {
    // 打开文件以进行写入
    std::ofstream outputFile("student_data.txt");

    // 检查文件是否成功打开
    if (outputFile.is_open()) {
        // 写入单个字符串
        outputFile << "John Doe" << std::endl;

        // 写入多个数据片段
        std::string name = "Alice Smith";
        int age = 22;
        double gpa = 3.75;
        outputFile << name << ", " << age << " years old, GPA: " << gpa << std::endl;

        // 写入多行内容
        outputFile << "Computer Science Student" << std::endl;
        outputFile << "University of Programming" << std::endl;

        // 关闭文件
        outputFile.close();
        std::cout << "数据成功写入文件!" << std::endl;
    } else {
        std::cout << "无法打开文件以进行写入。" << std::endl;
    }

    return 0;
}

编译程序:

g++ write_files.cpp -o write_files

运行可执行文件:

./write_files

示例输出:

数据成功写入文件!

验证文件内容:

cat student_data.txt

示例文件内容:

John Doe
Alice Smith, 22 years old, GPA: 3.75
Computer Science Student
University of Programming

关于写入文件的关键点:

  • 使用 << 运算符将数据写入文件
  • std::endl 用于添加新行
  • 可以写入字符串、数字和变量
  • 在写入之前始终检查文件是否已打开
  • 写入操作完成后关闭文件

你可以将写入文件类比为在笔记本上书写。ofstream 是你的笔,而文件是你记录信息的页面。

从文本文件中读取数据

在本步骤中,你将学习如何使用 C++ 中的 ifstream 类从文本文件中读取数据。基于之前的步骤,你将探索读取整行、单词以及整个文件的不同方法。

创建一个名为 read_files.cpp 的 C++ 文件:

touch ~/project/read_files.cpp

将以下代码添加到 read_files.cpp 文件中:

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

int main() {
    // 打开上一步创建的文件
    std::ifstream inputFile("student_data.txt");

    // 检查文件是否成功打开
    if (inputFile.is_open()) {
        // 读取整行
        std::string line;
        std::cout << "读取整行内容:" << std::endl;
        while (std::getline(inputFile, line)) {
            std::cout << line << std::endl;
        }

        // 重置文件指针到开头
        inputFile.clear();
        inputFile.seekg(0, std::ios::beg);

        // 读取单个单词
        std::cout << "\n读取单个单词:" << std::endl;
        std::string word;
        while (inputFile >> word) {
            std::cout << word << " ";
        }
        std::cout << std::endl;

        // 关闭文件
        inputFile.close();
    } else {
        std::cout << "无法打开文件以进行读取。" << std::endl;
    }

    return 0;
}

编译程序:

g++ read_files.cpp -o read_files

运行可执行文件:

./read_files

示例输出:

读取整行内容:
John Doe
Alice Smith, 22 years old, GPA: 3.75
Computer Science Student
University of Programming

读取单个单词:
John Doe Alice Smith, 22 years old, GPA: 3.75 Computer Science Student University of Programming

关于读取文件的关键点:

  • 使用 std::getline() 读取整行内容
  • 使用 >> 运算符读取单个单词
  • clear()seekg() 用于重置文件指针
  • 在读取之前始终检查文件是否已打开
  • 读取操作完成后关闭文件

你可以将读取文件类比为从书中提取信息。ifstream 是你的书签,帮助你浏览文本内容。

检查文件打开状态

在本步骤中,你将学习如何使用多种方法检查 C++ 中文件操作的状态,以验证文件是否成功打开并准备好进行读取或写入。

创建一个名为 file_status.cpp 的 C++ 文件:

touch ~/project/file_status.cpp

将以下代码添加到 file_status.cpp 文件中:

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

int main() {
    // 尝试打开一个现有文件以进行读取
    std::ifstream inputFile("student_data.txt");

    // 方法 1:使用 is_open() 检查文件状态
    if (inputFile.is_open()) {
        std::cout << "文件成功打开以进行读取。" << std::endl;

        // 执行读取操作
        std::string line;
        while (std::getline(inputFile, line)) {
            std::cout << "读取行: " << line << std::endl;
        }

        inputFile.close();
    } else {
        std::cout << "无法打开文件以进行读取。" << std::endl;
    }

    // 方法 2:使用 good() 检查文件状态
    std::ofstream outputFile("test_status.txt");

    if (outputFile.good()) {
        std::cout << "文件成功打开以进行写入。" << std::endl;
        outputFile << "测试文件状态" << std::endl;

        // 额外的状态检查
        if (outputFile) {
            std::cout << "文件处于可写入的良好状态。" << std::endl;
        }

        outputFile.close();
    } else {
        std::cout << "无法打开文件以进行写入。" << std::endl;
    }

    // 方法 3:多种状态检查方法
    std::ifstream checkFile("non_existent_file.txt");

    std::cout << "文件状态检查:" << std::endl;
    std::cout << "is_open(): " << (checkFile.is_open() ? "True" : "False") << std::endl;
    std::cout << "good(): " << (checkFile.good() ? "True" : "False") << std::endl;
    std::cout << "fail(): " << (checkFile.fail() ? "True" : "False") << std::endl;

    return 0;
}

编译程序:

g++ file_status.cpp -o file_status

运行可执行文件:

./file_status

示例输出:

文件成功打开以进行读取。
读取行: John Doe
读取行: Alice Smith, 22 years old, GPA: 3.75
读取行: Computer Science Student
读取行: University of Programming
文件成功打开以进行写入。
文件处于可写入的良好状态。
文件状态检查:
is_open(): False
good(): False
fail(): True

关于文件状态检查的关键点:

  • is_open():检查文件是否成功打开
  • good():检查是否未发生错误
  • fail():检查是否发生了错误
  • 在执行操作之前始终检查文件状态
  • 不同的方法提供了多种验证文件状态的方式

你可以将文件状态检查类比为旅程前的安全检查。这些方法有助于确保你的文件操作安全且成功。

处理文件读写错误

在本步骤中,你将学习如何处理 C++ 中文件读写操作期间可能发生的错误。理解错误处理对于创建健壮的文件操作程序至关重要。

创建一个名为 file_error_handling.cpp 的 C++ 文件:

touch ~/project/file_error_handling.cpp

将以下代码添加到 file_error_handling.cpp 文件中:

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

void writeToFile(const std::string& filename) {
    std::ofstream outputFile(filename);

    // 检查文件是否打开
    if (!outputFile) {
        // 如果文件无法打开,抛出异常
        throw std::runtime_error("无法打开文件以进行写入: " + filename);
    }

    try {
        // 尝试写入数据
        outputFile << "Hello, Error Handling!" << std::endl;
        outputFile << "This is a sample text." << std::endl;

        // 模拟写入错误(故意不推荐)
        if (outputFile.bad()) {
            throw std::runtime_error("写入操作失败");
        }
    }
    catch (const std::exception& e) {
        std::cerr << "写入过程中发生错误: " << e.what() << std::endl;
    }

    outputFile.close();
}

void readFromFile(const std::string& filename) {
    std::ifstream inputFile(filename);
    std::string line;

    // 检查文件是否打开
    if (!inputFile) {
        // 如果文件无法打开,抛出异常
        throw std::runtime_error("无法打开文件以进行读取: " + filename);
    }

    try {
        // 读取并打印文件内容
        std::cout << "文件内容:" << std::endl;
        while (std::getline(inputFile, line)) {
            std::cout << line << std::endl;
        }

        // 检查读取错误
        if (inputFile.bad()) {
            throw std::runtime_error("读取操作遇到错误");
        }
    }
    catch (const std::exception& e) {
        std::cerr << "读取过程中发生错误: " << e.what() << std::endl;
    }

    inputFile.close();
}

int main() {
    try {
        // 写入文件
        writeToFile("error_handling_example.txt");

        // 从文件读取
        readFromFile("error_handling_example.txt");

        // 尝试读取不存在的文件
        readFromFile("non_existent_file.txt");
    }
    catch (const std::exception& e) {
        std::cerr << "主错误: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

编译程序:

g++ file_error_handling.cpp -o file_error_handling

运行可执行文件:

./file_error_handling

示例输出:

文件内容:
Hello, Error Handling!
This is a sample text.
读取过程中发生错误: 无法打开文件以进行读取: non_existent_file.txt

关于文件错误处理的关键点:

  • 使用 try-catch 块处理潜在的异常
  • 在操作前后检查文件流状态
  • 使用 std::runtime_error 抛出有意义的错误信息
  • 处理不同类型的文件相关错误
  • 提供信息丰富的错误消息

你可以将错误处理类比为安全网。它捕获潜在问题并防止程序意外崩溃。

使用 fstream 处理二进制文件

在本步骤中,你将学习如何使用 C++ 中的 fstream 类处理二进制文件。二进制文件以原始二进制格式存储数据,这与文本文件不同,适用于高效存储结构化数据。

创建一个名为 binary_files.cpp 的 C++ 文件:

touch ~/project/binary_files.cpp

将以下代码添加到 binary_files.cpp 文件中:

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

// 用于演示二进制文件写入的简单结构体
struct Student {
    int id;
    char name[50];
    double gpa;
};

void writeBinaryFile() {
    std::fstream binaryFile("students.bin", std::ios::out | std::ios::binary);

    if (!binaryFile) {
        std::cerr << "打开文件以进行写入时出错!" << std::endl;
        return;
    }

    // 创建一些学生记录
    Student students[3] = {
        {1, "John Doe", 3.5},
        {2, "Alice Smith", 3.8},
        {3, "Bob Johnson", 3.2}
    };

    // 将整个结构体写入二进制文件
    binaryFile.write(reinterpret_cast<char*>(students), sizeof(students));

    binaryFile.close();
    std::cout << "二进制文件写入成功!" << std::endl;
}

void readBinaryFile() {
    std::fstream binaryFile("students.bin", std::ios::in | std::ios::binary);

    if (!binaryFile) {
        std::cerr << "打开文件以进行读取时出错!" << std::endl;
        return;
    }

    Student students[3];

    // 从二进制文件中读取整个结构体
    binaryFile.read(reinterpret_cast<char*>(students), sizeof(students));

    std::cout << "学生记录:" << std::endl;
    for (int i = 0; i < 3; ++i) {
        std::cout << "ID: " << students[i].id
                  << ", 姓名: " << students[i].name
                  << ", GPA: " << students[i].gpa << std::endl;
    }

    binaryFile.close();
}

int main() {
    // 写入二进制文件
    writeBinaryFile();

    // 读取二进制文件
    readBinaryFile();

    return 0;
}

编译程序:

g++ binary_files.cpp -o binary_files

运行可执行文件:

./binary_files

示例输出:

二进制文件写入成功!
学生记录:
ID: 1, 姓名: John Doe, GPA: 3.5
ID: 2, 姓名: Alice Smith, GPA: 3.8
ID: 3, 姓名: Bob Johnson, GPA: 3.2

关于二进制文件的关键点:

  • 使用 std::ios::binary 标志以二进制模式打开文件
  • 使用 write()read() 方法处理二进制数据
  • 使用 reinterpret_cast 进行类型转换
  • 适用于高效存储结构化数据
  • 保留数据的精确二进制表示

你可以将二进制文件类比为精确的蓝图。它们以内存中的原始形式存储数据,无需任何文本转换。

使用 seekg/seekp 定位文件指针

在本步骤中,你将学习如何使用 C++ 中的 seekg()seekp() 方法操作文件指针。seekg() 用于读取操作,seekp() 用于写入操作。这些方法允许你在文件中导航和修改特定位置。

创建一个名为 file_pointer.cpp 的 C++ 文件:

touch ~/project/file_pointer.cpp

将以下代码添加到 file_pointer.cpp 文件中:

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

void createSampleFile() {
    std::ofstream file("numbers.txt");
    for (int i = 1; i <= 10; ++i) {
        file << i << " ";
    }
    file.close();
}

void demonstrateSeekOperations() {
    // 以读写模式打开文件
    std::fstream file("numbers.txt", std::ios::in | std::ios::out);

    if (!file) {
        std::cerr << "打开文件时出错!" << std::endl;
        return;
    }

    // 从不同位置读取
    std::cout << "读取操作:" << std::endl;

    // 移动到第 5 个字节(字符位置)
    file.seekg(5);
    int value;
    file >> value;
    std::cout << "第 5 个字节的值: " << value << std::endl;

    // 移动到文件开头
    file.seekg(0);
    file >> value;
    std::cout << "第一个值: " << value << std::endl;

    // 在特定位置写入
    std::cout << "\n写入操作:" << std::endl;

    // 移动到特定位置并写入
    file.seekp(0);
    file << "100 ";

    // 重置文件指针并读取以验证
    file.seekg(0);
    file >> value;
    std::cout << "修改后的第一个值: " << value << std::endl;

    file.close();
}

int main() {
    // 创建一个包含数字的示例文件
    createSampleFile();

    // 演示 seek 操作
    demonstrateSeekOperations();

    return 0;
}

编译程序:

g++ file_pointer.cpp -o file_pointer

运行可执行文件:

./file_pointer

示例输出:

读取操作:
第 5 个字节的值: 4
第一个值: 1

写入操作:
修改后的第一个值: 10

关于文件指针的关键点:

  • seekg():移动读取指针(get pointer)
  • seekp():移动写入指针(put pointer)
  • 第一个参数是字节位置
  • 适用于文件的随机访问
  • 可以导航到特定位置

你可以将文件指针类比为文本编辑器中的光标。seekg()seekp() 帮助你精确地将光标移动到所需位置。

关闭文件并释放资源

在本步骤中,你将学习在 C++ 中正确关闭文件和管理资源的重要性,以防止内存泄漏并确保高效的文件处理。你将探索关闭文件的不同方法以及使用 RAII(资源获取即初始化)原则。

创建一个名为 file_resources.cpp 的 C++ 文件:

touch ~/project/file_resources.cpp

将以下代码添加到 file_resources.cpp 文件中:

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

// 手动关闭文件
void manualFileHandling() {
    std::ofstream outputFile("manual_file.txt");

    if (outputFile.is_open()) {
        outputFile << "手动管理的文件资源" << std::endl;

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

        std::cout << "文件已手动关闭。" << std::endl;
    }
}

// 使用 unique_ptr 的 RAII 文件处理
void raii_fileHandling() {
    try {
        // 使用 unique_ptr 管理文件资源
        std::unique_ptr<std::ofstream> file(new std::ofstream("raii_file.txt"));

        if (file && file->is_open()) {
            *file << "RAII 管理的文件资源" << std::endl;
            std::cout << "RAII 文件处理成功。" << std::endl;
        }
        // 当 unique_ptr 超出作用域时,文件会自动关闭
    }
    catch (const std::exception& e) {
        std::cerr << "RAII 文件处理出错: " << e.what() << std::endl;
    }
}

// 基于作用域的文件处理
void scopeBasedFileHandling() {
    {
        // 文件在超出作用域时会自动关闭
        std::ofstream scopedFile("scoped_file.txt");

        if (scopedFile.is_open()) {
            scopedFile << "基于作用域的文件资源管理" << std::endl;
            std::cout << "基于作用域的文件处理成功。" << std::endl;
        }
    } // 文件在此处自动关闭
}

int main() {
    // 演示不同的文件资源管理技术
    manualFileHandling();
    raii_fileHandling();
    scopeBasedFileHandling();

    return 0;
}

编译程序:

g++ file_resources.cpp -o file_resources

运行可执行文件:

./file_resources

示例输出:

文件已手动关闭。
RAII 文件处理成功。
基于作用域的文件处理成功。

关于关闭文件和管理资源的关键点:

  • 使用完文件后始终关闭文件
  • 使用 close() 方法手动关闭文件
  • 利用 RAII 原则
  • 使用基于作用域的资源管理
  • 防止资源泄漏
  • 处理文件操作期间的异常

你可以将文件资源类比为从图书馆借书。使用完书后(关闭文件)要记得归还,以保持图书馆(系统资源)的井然有序。

总结

在本实验中,你学习了如何使用 C++ 标准库中的 ofstreamifstream 类打开文件。你探索了检查文件打开状态、将文本数据写入文件以及从文本文件中读取数据的过程。此外,你还掌握了如何处理文件读写错误、使用 fstream 处理二进制文件、使用 seekg/seekp 定位文件指针,以及正确关闭文件和释放资源。这些基本的文件操作对于在 C++ 应用程序中管理数据存储和检索至关重要。

您可能感兴趣的其他 C++ 教程