简介
在本实验中,你将学习如何在 C++ 中执行各种文件操作。实验内容包括打开文件进行读取和写入、将文本数据写入文件、从文本文件中读取数据、检查文件打开状态、处理文件读写错误、处理二进制文件、定位文件指针以及关闭文件以释放资源。你将通过使用 C++ 标准库中的基本文件流类 ofstream
和 ifstream
来与文件进行交互,获得实践经验。通过本实验,你将对 C++ 编程中的文件处理有扎实的理解。
在本实验中,你将学习如何在 C++ 中执行各种文件操作。实验内容包括打开文件进行读取和写入、将文本数据写入文件、从文本文件中读取数据、检查文件打开状态、处理文件读写错误、处理二进制文件、定位文件指针以及关闭文件以释放资源。你将通过使用 C++ 标准库中的基本文件流类 ofstream
和 ifstream
来与文件进行交互,获得实践经验。通过本实验,你将对 C++ 编程中的文件处理有扎实的理解。
在本步骤中,你将学习如何使用 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;
}
让我们分解关键概念:
#include <fstream>
:包含文件流库std::ofstream
:用于写入文件的输出文件流std::ifstream
:用于读取文件的输入文件流is_open()
:检查文件是否成功打开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
抛出有意义的错误信息你可以将错误处理类比为安全网。它捕获潜在问题并防止程序意外崩溃。
在本步骤中,你将学习如何使用 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
进行类型转换你可以将二进制文件类比为精确的蓝图。它们以内存中的原始形式存储数据,无需任何文本转换。
在本步骤中,你将学习如何使用 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()
方法手动关闭文件你可以将文件资源类比为从图书馆借书。使用完书后(关闭文件)要记得归还,以保持图书馆(系统资源)的井然有序。
在本实验中,你学习了如何使用 C++ 标准库中的 ofstream
和 ifstream
类打开文件。你探索了检查文件打开状态、将文本数据写入文件以及从文本文件中读取数据的过程。此外,你还掌握了如何处理文件读写错误、使用 fstream
处理二进制文件、使用 seekg/seekp
定位文件指针,以及正确关闭文件和释放资源。这些基本的文件操作对于在 C++ 应用程序中管理数据存储和检索至关重要。