文件操作
数据流
在cpp中,流(stream)是一个抽象概念,用于描述如何从一个位置到又一个位置传输数据。流主要用于I/O操作。
数据流包括两大类:1. 输入流 (istream):数据从某个源流入程序, 2. 输出流(ostream):数据从程序流向某个目的地。
根据操作对象不同分为文件流、字符串流、控制台流。
控制台流
控制台流(<iostream>)主要用于标准输入输出操作的一部分。这些流提供了一个接口,用于与用于进行交互,即从键盘读取和向屏幕输出,无论程序在那种操作系统或平台上运行。
iostream:同时包括istream和osteam,是一种多继承的关系,在程序应用中可以只包含头文件<iostream>。
常见对象有:cin(标准输入),cout(标准输出),cerr(用于显示错误信息)。
<<和>>运算符,是ostream类使用友元函数的方式对各种基本数据类型重载了<<操作符,使我们能够方便地将数据输出到流中。
文件流
文件流主要包括输入文件流 <ifstream>、输出文件流 <ofstream>和输入输出文件流 <fstream>,这些类都定义在<fstream>头文件中。
与标准输入输出流 如cin和cout不同,文件流需要指定具体的文件来操作。因此,我们需要创建一个流对象并为其指定一个文件名和其他相关属性。
ofstream类的默认构造函数原形为:
            
            
              cpp
              
              
            
          
          ofstream::ofstream(const char *filename, int mode = ios::out, int pmode = filebuf::openprot);其中filmname表示指定要打开的文件名。
mode是一个标志位,用于指定如何打开文件。默认值是ios::out,意味着文件以输出模式打开
pmode是一个与平台相关的权限参数,指定了文件的权限。
| 类型 | 解释 | 
|---|---|
| ios::app | 输出追加模式。当写入文件时,数据会被追加到文件的末尾,而不是覆盖文件的内容。 | 
| ios::ate | 初始位置在文件的末尾,但你可以移动到文件中的任何位置进行读写操作。 | 
| ios::binary | 文件以二进制模式打开。不使用这个模式时,默认为文本模式。 | 
| ios::in | 文件以输入模式打开(通常与 ifstream一起使用)。 | 
| ios::out | 文件以输出模式打开(默认值)。 | 
| ios::trunc | 如果文件已存在,其内容将被截断或删除。 | 
| ios:nocreate | 不建立文件,所以文件不存在时打开失败 | 
| ios:.noreplace | 不覆盖文件,打开文件时如果文件存在失败 | 
打开文件属性值
| 类型 | 解释 | 
|---|---|
| 0 | 普通文件,打开访问 | 
| 1 | 只读文件 | 
| 2 | 隐含文件 | 
| 4 | 系统文件 | 
"或"或者"+"把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。 文件使用完后可以使用close成员函数关闭文件。
ios::app,当你用这种模式打开文件时,先检查文件的状态。例如,你可以使用 file.is_open() 来确定文件是否成功打开,以及使用 file.fail() 来检查是否有任何I/O错误。这有助于确保文件操作的安全和有效。
字符串流
字符串流定义在<sstream>头文件中,主要有以下三种类型的字符串流:
- istringstream: 输入字符串流,允许从一个- std::string对象中读取。
- ostringstream: 输出字符串流,允许写入到一个- std::string对象。
- stringstream: 同时支持读写操作的字符串流。
文件处理
C++的文件处理也可以看作为一个对象,使用文件流的类,使用头文件<fstream>,处理的时候有文本文件 和二进制文件之分,主要的区别就是存储的形式。
文件处理可以概括成如下几个过程:
- 包含头文件
- 创建文件流对象
- 打开文件
- 文件读写
- 关闭文件
打开文件
打开文件的核心:打开文件涉及到通知操作系统你希望访问文件的特定部分(例如读、写或两者兼而有之),并且通常会得到一个文件句柄或文件描述符,该描述符后续可用于读写操作。
下面是open()函数的标准语法,open()是ifstream、ofstream和fstream类的成员函数,用于打开文件。
            
            
              cpp
              
              
            
          
          void open(const char *filename, ios::openmode mode = ios::in | ios::out);open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。

以上的不同模式标志,可以组合使用为文件指定复杂的打开行为。
例如:
- 写入模式与截断模式
            
            
              cpp
              
              
            
          
          ofstream outf;
outf.open("file.txt", ios::out | ios::trunc);ios::trunc :当与ios::out一起使用时,这个标志表示如果文件已经存在,则其内容应被截断或清空。如果不指定这个标志并且文件已存在,写入操作通常会覆盖文件的现有内容,从文件的开头开始。
- 读写模式
            
            
              cpp
              
              
            
          
          fstream file;
file.open("file.txt", ios::out | ios::in);结合ios::in和ios::out,意味着你可以对文件进行读写操作。当使用这种模式打开文件时,现有的文件内容不会被自动截断或清空。你可以在文件中任意地移动,进行读和写操作。
文件的写入与输出
写入文件
在cpp中,可以使用流插入运算符(<<)将数据写入文件,类似于将信息输出到控制台的方式。
对比控制台输出和文件输出:
            
            
              cpp
              
              
            
          
          std::cout << "Hello, World!";这是cout代表标准输出的ostream类实例。
            
            
              cpp
              
              
            
          
          std::ofstream outFile("filename.txt");
outFile << "Hello, File!";outFile 是 ofstream 类的实例。 ofstream 代表"输出文件流",允许将数据写入文件。
读取文件
从文件读取涉及流提取运算符 ( >> ),类似于从键盘获取输入。唯一不同的是,在这里使用的是 ifstream 或 fstream 对象,而不是 cin 对象。
关闭文件
在cpp程序终止时,他会自动关闭并且刷新所有流,释放所有分配的内存,并关闭所有打开的文件,但显示关闭文件是一个好习惯。
使用完文件后关闭文件的原因如下
- To make sure that all buffered data gets written.确保所有缓冲数据都被写入。
- To release the resources associated with the file.释放与该文件关联的资源。
- To prevent any potential data corruption.防止任何潜在的数据损坏。
下面是close()函数的标准语法,close() 函数是 fstream、ifstream 和ofstream 对象的一个成员。
void close()
文件写入简单示例:
            
            
              cpp
              
              
            
          
          #include<iostream>
#include<fstream>
using namespace std;
int main(){
    // 创建流对象
    ofstream outf;
    // 打开文件
    outf.open("file.txt", ios:: app);
    // 写入数据
    outf << "Hello World" << endl;
    // 关闭文件
    outf.close();
    return 0;
}文件读取的简单示例:
            
            
              CPP
              
              
            
          
          #include<iostream>
#include<fstream> //文件流的头文件
using namespace std;
int main()
{
    char a;
    ifstream infile; //定义ifstream类(输入文件流类)对象outfile
    infile.open("file.txt");//打开文件 使文件流与c++.txt文件建立关联
    while (!infile.eof())
    {
        infile.get(a); //依次获取文件中每个字符 并输出
        cout << a;
    }
    infile.close(); //关闭文件 使文件流与c++.txt文件断开关联
}这种方法效率低,不建议使用。
第二种方法:
            
            
              cpp
              
              
            
          
          char buf[1024] = {0};
while (ifs >> buf) {
    cout << buf << endl;
}第三种:
            
            
              cpp
              
              
            
          
          char buf[1024] = {0};
while (ifs.getline(buf, sizeof(buf))) {
    cout << buf << endl;
}第四种:
            
            
              cpp
              
              
            
          
          string buf;
while (getline(ifs, buf)) {
    cout << buf << endl;
}
ifs.close();二进制文件读写
二进制写文件主要利用流对象调用成员函数write(),这个函数直接从内存中的某个位置(由buffer指针指定)写入指定的字节数(len)到文件中。
函数原型:ostream& write(const char*buffer,int len);
            
            
              cpp
              
              
            
          
          #include<iostream>
#include<fstream> //文件流的头文件
using namespace std;
class Student {
public:
    Student() {}
    Student(string name,int age) :name(name), age(age) {}
protected:
    string name;
    int age;
};
int main() {
    ofstream bof;
    Student s1("张三", 100);
    bof.open("student.txt", ios::out|ios::binary);
    bof.write((const char*) & s1, sizeof(Student));
    bof.close();
    return 0;
}读取文件用read 函数从文件中读取指定的字节数并将其放入指定的内存位置。
            
            
              cpp
              
              
            
          
          ifstream bif;
    bif.open("student.txt", ios::in | ios::binary);
    if (!bif.is_open()) {
        cout << "文件打开失败" << endl;
        return 0;
    }
    Student s2;
    bif.read((char*)&s2, sizeof(Student));
    cout << s2.name << " " << s2.age << endl;
    bif.close();fstream文件操作
打开文件和关闭文件
打开文件fstream可以在生命流对象时传入文件名打开文件,也可以使用open()函数打开文件。
文件打开后必须关闭,fstream提供了close()函数关闭文件。
打开文件
使用构造函数声明对象时打开文件:
fstream ioFile("data.txt", ios::in | ios::out);
使用open()函数打开文件:
            
            
              cpp
              
              
            
          
          fstream file;
file.open("example.txt", ios::in | ios::out);如果只传文件名,系统会自动根据文件类型选择默认的打开方式。
- ios::in:读取模式
- ios::out:写入模式
- ios::app:追加模式。数据会被写入文件的末尾而不是覆盖已有内容。
- ios::trunc:如果文件存在,则先删除文件的内容,然后再打开它。
- ios::binary:以二进制模式打开文件。
模式和属性可以单独使用,也可以混合使用。在混合使用时,需要使用逻辑连接符或|链接。
ios::out会默认清空文件,即ios::out|ios::trunc打开文件的同时清空文件。如果不想清空文件,那么设置读写模式为ios::out|ios::app,以这种模式打开文件后,是以追加内容的方式写入文件。
fstream提供了多种读写操作,包括:
- <<和- >>:这些操作符用于向文件写入数据和从文件读取数据。
- read()和- write():这些函数用于处理二进制文件。
- put()和- get():这些函数分别用于写入和读取单个字符。
- getline():这个函数用于从文件中读取一行文本。
示例:
读取文本文件:
            
            
              cpp
              
              
            
          
          ifstream file("example.txt");
string line;
while(getline(file, line)) {
    cout << line << endl;
}
file.close();读取二进制文件:
            
            
              cpp
              
              
            
          
          ifstream file("binaryExample.bin", ios::binary);
int number;
file.read((char*)&number, sizeof(number));
file.close();- 文本文件 :这些文件主要包含文本,如.txt。你通常会使用逐行读取/写入的方式来处理它们。
- 二进制文件:这些文件包含二进制数据,如图像、音频或编译后的程序。当处理这些文件时,你会使用块读写的方式,这意味着你可能会一次读取/写入多个字节。
完整示例:
            
            
              cpp
              
              
            
          
          #include <iostream>
#include <fstream>  // 1. 包含头文件
#include <string>
using namespace std;
int main() {
    string str;
    fstream iofile;  // 2. 创建对象
    // 3. 打开文件并清空内容
    iofile.open("file.txt", ios::out | ios::in | ios::trunc);
    // 4. 写入数据
    iofile << "这里是写入内容测试" << endl;
    iofile << "this is test" << endl;
    iofile.close();  // 5. 关闭文件
    cout << "写入完毕" << endl;
    // 重新打开文件进行读取
    iofile.open("file.txt", ios::out | ios::in);
    while (getline(iofile, str))  // 循环读取
    {
        cout << str << endl;
    }
    iofile.close();
    cout << "读取完毕" << endl;
    return 0;
}二进制数据读写文件:
            
            
              cpp
              
              
            
          
          #include <iostream>
#include <fstream>
using namespace std;
int main() {
    int numbers[] = {10, 20, 30, 40, 50};
    fstream iofile;
    // 1. 打开文件以进行二进制写入
    iofile.open("binaryfile.bin", ios::out | ios::binary | ios::trunc);
    iofile.write((char*) &numbers, sizeof(numbers));
    iofile.close();
    cout << "数据已写入二进制文件" << endl;
    int readNumbers[5] = {0};
    // 2. 打开文件以进行二进制读取
    iofile.open("binaryfile.bin", ios::in | ios::binary);
    iofile.read((char*) &readNumbers, sizeof(readNumbers));
    iofile.close();
    cout << "从二进制文件读取的数据:" << endl;
    for(int i = 0; i < 5; i++) {
        cout << readNumbers[i] << " ";
    }
    cout << endl;
    return 0;
}文件定义与大小
当你在处理文件时,经常需要控制文件的读写位置或查询其大小。C++提供了一组非常强大的工具来实现这一目的,下面将详细介绍这些功能及其用法。
文件定位:seekg() 和 seekp()
seekg() 和 seekp() 分别用于设置输入和输出流的位置。
- seekg():设置输入流的位置(对应读操作)。
- seekp():设置输出流的位置(对应写操作)。
这些函数需要两个参数:
- offset:这是从给定起点移动的字节量。它可以是正数(向前移动)或负数(向后移动)。
- origin :这定义了从哪里开始计算偏移。常用的起点有:
- ios::beg:从文件开始处。
- ios::cur:从文件的当前位置。
- ios::end:从文件的末尾。
 
示例:
            
            
              cpp
              
              
            
          
          fstream file("example.txt", ios::in | ios::out);
// 将读指针从文件开始处向后移动2个字节
file.seekg(2, ios::beg);
// 将写指针从当前位置向后移动2个字节
file.seekp(2, ios::cur);2. 获取文件大小:tellg() 和 tellp()
这两个函数返回当前的读或写位置,通常表示为从文件开始到当前位置的字节数。
- tellg():获取输入流的当前位置。
- tellp():获取输出流的当前位置。
如果你想知道整个文件的大小,一个常见的方法是将读指针移动到文件的末尾,然后使用 tellg()。
示例:
            
            
              cpp
              
              
            
          
          fstream file("example.txt", ios::in | ios::out);
// 将读指针移动到文件末尾
file.seekg(0, ios::end);
// 获取当前位置,即文件大小
streampos size = file.tellg();
cout << "文件大小是: " << size << " 字节" << endl;注意:
- 在操作完成后,可能需要将文件指针重新定位到适当的位置,以便进行后续的读/写操作。
- 尝试读取超出文件大小的位置可能会导致未定义的行为,通常是读取失败。