介绍
在这个 Lab 中,你将学习如何在 C++ 中执行各种文件操作。本 Lab 涵盖了打开文件进行读取和写入、向文件写入文本数据、从文本文件读取数据、检查文件打开状态、处理文件读/写错误、使用二进制文件、定位文件指针以及关闭文件以释放资源。你将获得使用 C++ 标准库中的基本文件流类 ofstream 和 ifstream 与文件交互的实践经验。完成本 Lab 后,你将对 C++ 编程中的文件处理有一个扎实的理解。
在这个 Lab 中,你将学习如何在 C++ 中执行各种文件操作。本 Lab 涵盖了打开文件进行读取和写入、向文件写入文本数据、从文本文件读取数据、检查文件打开状态、处理文件读/写错误、使用二进制文件、定位文件指针以及关闭文件以释放资源。你将获得使用 C++ 标准库中的基本文件流类 ofstream 和 ifstream 与文件交互的实践经验。完成本 Lab 后,你将对 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 << "File opened for writing successfully!" << std::endl;
outputFile.close(); // 关闭文件
} else {
std::cout << "Unable to open file for writing." << std::endl;
}
// 使用 ifstream 打开文件进行读取
std::ifstream inputFile("example.txt");
// 检查文件是否成功打开
if (inputFile.is_open()) {
std::cout << "File opened for reading successfully!" << std::endl;
inputFile.close(); // 关闭文件
} else {
std::cout << "Unable to open file for reading." << std::endl;
}
return 0;
}
让我们分解一下关键概念:
#include <fstream>: 包含文件流库std::ofstream: 用于写入文件的输出文件流std::ifstream: 用于读取文件的输入文件流is_open(): 检查文件是否成功打开close(): 操作完成后关闭文件编译程序:
g++ file_operations.cpp -o file_operations
运行可执行文件:
./file_operations
示例输出:
File opened for writing successfully!
File opened for reading successfully!
关于文件流的一些重要注意事项:
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 << "Data written to file successfully!" << std::endl;
} else {
std::cout << "Unable to open file for writing." << std::endl;
}
return 0;
}
编译程序:
g++ write_files.cpp -o write_files
运行可执行文件:
./write_files
示例输出:
Data written to file successfully!
验证文件内容:
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 << "Reading entire lines:" << std::endl;
while (std::getline(inputFile, line)) {
std::cout << line << std::endl;
}
// 重置文件指针到开头
inputFile.clear();
inputFile.seekg(0, std::ios::beg);
// 读取单个单词
std::cout << "\nReading individual words:" << std::endl;
std::string word;
while (inputFile >> word) {
std::cout << word << " ";
}
std::cout << std::endl;
// 关闭文件
inputFile.close();
} else {
std::cout << "Unable to open file for reading." << std::endl;
}
return 0;
}
编译程序:
g++ read_files.cpp -o read_files
运行可执行文件:
./read_files
示例输出:
Reading entire lines:
John Doe
Alice Smith, 22 years old, GPA: 3.75
Computer Science Student
University of Programming
Reading individual words:
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 << "File opened successfully for reading." << std::endl;
// 执行读取操作
std::string line;
while (std::getline(inputFile, line)) {
std::cout << "Read line: " << line << std::endl;
}
inputFile.close();
} else {
std::cout << "Failed to open file for reading." << std::endl;
}
// 方法 2: 使用 good() 检查文件状态
std::ofstream outputFile("test_status.txt");
if (outputFile.good()) {
std::cout << "File opened successfully for writing." << std::endl;
outputFile << "Testing file status" << std::endl;
// 额外的状态检查
if (outputFile) {
std::cout << "File is in a good state for writing." << std::endl;
}
outputFile.close();
} else {
std::cout << "Failed to open file for writing." << std::endl;
}
// 方法 3: 多种状态检查方法
std::ifstream checkFile("non_existent_file.txt");
std::cout << "File status checks:" << 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
示例输出:
File opened successfully for reading.
Read line: John Doe
Read line: Alice Smith, 22 years old, GPA: 3.75
Read line: Computer Science Student
Read line: University of Programming
File opened successfully for writing.
File is in a good state for writing.
File status checks:
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("Unable to open file for writing: " + filename);
}
try {
// 尝试写入数据
outputFile << "Hello, Error Handling!" << std::endl;
outputFile << "This is a sample text." << std::endl;
// 模拟写入错误(不推荐这样做)
if (outputFile.bad()) {
throw std::runtime_error("Write operation failed");
}
}
catch (const std::exception& e) {
std::cerr << "Error during writing: " << 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("Unable to open file for reading: " + filename);
}
try {
// 读取并打印文件内容
std::cout << "File contents:" << std::endl;
while (std::getline(inputFile, line)) {
std::cout << line << std::endl;
}
// 检查读取错误
if (inputFile.bad()) {
throw std::runtime_error("Read operation encountered an error");
}
}
catch (const std::exception& e) {
std::cerr << "Error during reading: " << 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 << "Main error: " << e.what() << std::endl;
return 1;
}
return 0;
}
编译程序:
g++ file_error_handling.cpp -o file_error_handling
运行可执行文件:
./file_error_handling
示例输出:
File contents:
Hello, Error Handling!
This is a sample text.
Error during reading: Unable to open file for reading: 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 << "Error opening file for writing!" << 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 << "Binary file written successfully!" << std::endl;
}
void readBinaryFile() {
std::fstream binaryFile("students.bin", std::ios::in | std::ios::binary);
if (!binaryFile) {
std::cerr << "Error opening file for reading!" << std::endl;
return;
}
Student students[3];
// 从二进制文件读取整个结构体
binaryFile.read(reinterpret_cast<char*>(students), sizeof(students));
std::cout << "Student Records:" << std::endl;
for (int i = 0; i < 3; ++i) {
std::cout << "ID: " << students[i].id
<< ", Name: " << 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
示例输出:
Binary file written successfully!
Student Records:
ID: 1, Name: John Doe, GPA: 3.5
ID: 2, Name: Alice Smith, GPA: 3.8
ID: 3, Name: Bob Johnson, GPA: 3.2
关于二进制文件的关键点:
std::ios::binary 标志来指定二进制模式write() 和 read() 方法处理二进制数据reinterpret_cast 在类型之间进行转换你可以将二进制文件想象成一份精确的蓝图。它们存储的数据与其在内存中的存在方式完全一致,无需进行任何文本转换。
在这一步,你将学习如何使用 C++ 中的 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 << "Error opening file!" << std::endl;
return;
}
// 读取操作
std::cout << "Reading operations:" << std::endl;
// 移动到第 5 个字节(字符位置)
file.seekg(5);
int value;
file >> value;
std::cout << "Value at 5th byte: " << value << std::endl;
// 移动到文件开头
file.seekg(0);
file >> value;
std::cout << "First value: " << value << std::endl;
// 在特定位置写入
std::cout << "\nWriting operations:" << std::endl;
// 移动到特定位置并写入
file.seekp(0);
file << "100 ";
// 重置文件指针并读取以验证
file.seekg(0);
file >> value;
std::cout << "Modified first value: " << value << std::endl;
file.close();
}
int main() {
// 创建一个包含数字的示例文件
createSampleFile();
// 演示 seek 操作
demonstrateSeekOperations();
return 0;
}
编译程序:
g++ file_pointer.cpp -o file_pointer
运行可执行文件:
./file_pointer
示例输出:
Reading operations:
Value at 5th byte: 4
First value: 1
Writing operations:
Modified first value: 100
关于文件指针的关键点:
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 << "Manually managed file resource" << std::endl;
// 显式关闭文件
outputFile.close();
std::cout << "File closed manually." << 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-managed file resource" << std::endl;
std::cout << "RAII file handling successful." << std::endl;
}
// 当 unique_ptr 离开作用域时,文件会自动关闭
}
catch (const std::exception& e) {
std::cerr << "Error in RAII file handling: " << e.what() << std::endl;
}
}
// 基于作用域的文件处理
void scopeBasedFileHandling() {
{
// 文件在离开作用域时会自动关闭
std::ofstream scopedFile("scoped_file.txt");
if (scopedFile.is_open()) {
scopedFile << "Scope-based file resource management" << std::endl;
std::cout << "Scoped file handling successful." << std::endl;
}
} // 文件在此处自动关闭
}
int main() {
// 演示不同的文件资源管理技术
manualFileHandling();
raii_fileHandling();
scopeBasedFileHandling();
return 0;
}
编译程序:
g++ file_resources.cpp -o file_resources
运行可执行文件:
./file_resources
示例输出:
File closed manually.
RAII file handling successful.
Scoped file handling successful.
关于关闭文件和管理资源的关键点:
close() 方法进行手动关闭你可以将文件资源想象成从图书馆借书。用完后务必归还书(关闭文件),以保持图书馆(系统资源)的整洁有序。
在这个实验中,你学习了如何使用标准库中的 ofstream 和 ifstream 类在 C++ 中打开文件。你探索了检查文件打开状态、向文件写入文本数据以及从文本文件中读取数据的过程。此外,你还了解了如何处理文件读/写错误、使用 fstream 处理二进制文件、使用 seekg/seekp 定位文件指针,以及如何正确关闭文件和释放资源。这些基本的文件操作对于管理 C++ 应用程序中的数据存储和检索至关重要。