如何使用 <fstream> 类进行文件的 I/O 处理
### 如何使用 `<fstream>` 类进行文件的 I/O 处理 #### 摘要 传统的文件 I/O 库如 Unix 的 `<io.h>` 和 `<stdio.h>`,由于其程序接口的原因,在很大程度上强制程序员进行某些处理,缺乏类型安全和国际化支持。C++ 的 `<fstream>` 库则在文件的 I/O 方面提供了一个增强的、面向对象的、具有国际化意识的库。本文将详细介绍如何使用 `<fstream>` 库进行文件的 I/O 处理,并利用它来编写易于跨平台的代码。 #### 传统文件 I/O 库的问题 大多数 C++ 程序员都熟悉多种文件 I/O 库。首先是传统的 Unix 风格的库,它由一些低级函数如 `read()` 和 `open()` 组成。其次是 ANSI C 的 `<stdio.h>` 库,它包含 `fopen()` 和 `fread()` 等函数。除此之外,还有一些专有的库或框架,例如 MFC,它有许多自己的文件处理类。然而,这些库往往很难跨平台使用。更糟糕的是,上述 C 库由于其程序接口的原因,在很大程度上强制程序员进行某些处理,且缺乏类型安全性支持。 #### `<fstream>` 库的优势 标准 C++ 提供了一个增强的、面向对象的、具有国际化意识的 `<fstream>` 库。这个库包含了一系列派生于标准 `ios_base` 和 `ios` 类的类模板。因此,`<fstream>` 提供了高级的自动控制机制和健壮性。 #### 使用 `<fstream>` 类进行文件的 I/O 处理 **第一步:创建文件流** - **输入文件流(`ifstream`)**:支持重载的 `>>` 操作符。 - **输出文件流(`ofstream`)**:支持重载的 `<<` 操作符。 - **结合输入输出的文件流(`fstream`)**:同时支持输入和输出操作。 以下是一个简单的示例,展示如何使用 `ifstream` 对象读取文件: ```cpp #include <iostream> #include <string> #include <fstream> #include <cstdlib> using namespace std; int main() { string s; cout << "Enter dictionary file: "; cin >> s; ifstream dict(s.c_str()); if (!dict) // Were there any errors on opening? exit(-1); while (dict >> s) { cout << s << '\n'; } } ``` 在这个例子中,必须调用 `string::c_str()` 成员函数,因为 `<fstream>` 对象只接受常量字符串作为文件名。当将文件名作为参数传递时,构造函数试图打开指定的文件。接下来,我们使用重载的 `!` 操作符来检查文件的状态。如果出现错误,该操作符返回 `true`。最后一行是一个循环,每次迭代都从文件读取一个单词,将其复制到 `s` 中,然后显示出来。值得注意的是,我们不必显式地检查 EOF,因为重载操作符 `>>` 会自动处理这种情况。此外,我们也不用显式地关闭文件,因为析构函数会自动为我们执行这一操作。 **过时和废弃的 `<fstream.h>` 库** 支持 `ios::nocreate` 和 `ios::noreplace` 标志。但是,新的 `<fstream>` 库已经取代了 `<fstream.h>` 并不再支持这两个标志。 **文件的打开模式** 如果你不显式指定打开模式,`fstream` 类将使用默认值。例如,`ifstream` 默认以读方式打开文件并将文件指针置于文件的开始处。为了向文件写入数据,需要创建一个 `ofstream` 对象。 `<fstream>` 定义了以下打开模式和文件属性: - `ios::app` // 从后面添加 - `ios::ate` // 打开并找到文件尾 - `ios::binary` // 二进制模式 I/O(与文本模式相对) - `ios::in` // 只读打开 - `ios::out` // 写打开 - `ios::trunc` // 将文件截为 0 长度 可以使用位域操作符 OR 来组合这些标志: ```cpp ofstream logfile("login.dat", ios::binary | ios::app); fstream logfile("database.dat", ios::in | ios::out); ``` **第二步:设置文件的位置** 文件具有一个逻辑指针,它指向文件中的某个偏移位置。可以通过调用 `seekp()` 成员函数以字节为单位将这个指针定位到文件的任意位置。为了获取从文件开始处到当前偏移的字节数,可以调用 `seekp()`。下面是一个示例,程序将文件位置前移 10 个字节,然后调用 `tellp()` 报告新位置: ```cpp ofstream fout("parts.txt"); fout.seekp(10); // 从 0 偏移开始前进 10 个字节 cout << "New position: " << fout.tellp(); // 显示 10 ``` #### 结论 通过使用 `<fstream>` 库,我们可以轻松地处理文件 I/O,并且能够写出更加健壮和跨平台的代码。此外,利用 `<fstream>` 库提供的面向对象特性,可以更容易地维护和扩展代码。希望本文对您理解和使用 `<fstream>` 进行文件 I/O 处理有所帮助。