1 基本概念
文件 (file)
存储在磁盘上的数据集合,可以是文本、二进制等格式,具有名称、大小、类型等属性。
流 (stream)
一连串的字节,是一种抽象的数据传输方式。
在C++中,文件操作是基于流的概念,有3种主要类型的流:
- 输入流 (istream):允许程序从源(如键盘、文件)读取数据。
- 输出流 (ostream):允许程序将数据发送到目标(如显示器、文件)。
- 输入/输出流 (iostream):结合了输入流和输出流的功能。
2 文件操作
使用#include <fstream>
处理文件的输入输出。
ifstream:输入文件流,用于从文件中读取数据。
ofstream:输出文件流,用于向文件写入数据。
fstream:结合ifstream和ofstream功能,支持读写文件。
3 基本使用方法
3.1 包含必要的头文件
#include <fstream>
#include <iostream>
#include <string>
3.2 操作步骤
1)定义文件流
想使用文件流对文件进行操作,需要先定义它。
// there are 3 ways to define filestream
// 1) declare input stream
ifstream inFile;
// 2) declare output stream
ofstream outFile;
// 3) declare input&output stream
fstream file;
2)打开文件
进行文件操作之前,需要先打开文件。
打开文件:void open(const char *filename, ios::openmode mode);
filename:待打开文件的名称和位置
mode:文件被打开的模式
常用打开模式:
mode | Description |
---|---|
ios::in | 打开文件用于读取。 |
ios::out | 打开文件用于写入。 |
ios::trunc | 若文件已经存在,则在打开文件之前清空其内容,即把文件长度设为 0。 |
ios::app | 追加模式。所有写入都追加到文件末尾。 |
ios::ate | 文件打开后定位到文件末尾。 |
ios::binary | 二进制方式(默认是文本方式) |
ios::nocreate | 不创建的方式 |
ios::norepalce | 不替换 |
inFile.open("file.txt",ios::in); //读取文件中的数据
outFile.open("file2.txt",ios::out|ios::trunc); //写数据进文件中
file.open("file.txt"); //读写文件中的数据(无参数即默认方式打开)
// 判断文件是否打开成功
if(!file.is_open())
{
cout<<"file open failed!"<<endl;
exit(-1);
}
3) 读写文件
使用流运算符>>
和<<
分别进行读取和写入。(适用于文本形式)
// read
string dataBuffer;
inFile >> dataBuffer;
// write
outFile << "Hello World!" <<endl;
使用read()
和write()
分别进行读取和写入。(适用于二进制形式)
istream & read(char* buffer, int count);
ostream & write(char* buffer, int count);
buffer:指定起始位置
count:字节个数
class Student
{
char name[20];
int age;
};
Student stu;
// read
ifstream inFile("test.dat",ios::in|ios::binary);
if(!inFile)
{
exit(-1);
}
while(inFile.read((char*)&stu, sizeof(stu)))//一直读到文件结束
{
cout << stu.name << "" << stu.age << endl;
}
// gcount()
// write
/*
调用 write()函数时并没有指定这些字节写入文件中的具体位置。
事实上,write()会从 文件写指针 指向的位置将二进制数据写入。
文件写指针:
是ofstream/fstream对象内部维护的一个变量, 文件刚打开时,指向文件的开头.
(如果以 ios::app 方式打开,则指向文件末尾)
用 write() 方法写入 n 个字节,写指针指向的位置就向后移动 n 个字节。
*/
ofstream outFile("test.dat",ios::out|ios::binary);
while(cin >> stu.name >> stu.age)
{
outFile.write((char*)&stu, sizeof(stu));
}
使用get()
和put()
分别进行读取和写入。(适用于逐个读写)
int get();
istream& get (char& c);
ostream& put (char c);
char c;
// read
while( (c=inFile.get()) && c!=EOF) // while(inFile.get(c)){}
{//EOF:输入的末尾
cout << c;
}
// write
while(cin >> c)
{
outFile.put(c);
}
getline()读取一行
istream & getline(char* buf, int bufSize);
读取buf-1个字符,读到\n为止(不包括\n)
istream & getline(char* buf, int bufSize, char delim);
读到delim字符为止(不包括delim)
// read line
string lineBuffer;
getline(inFile, lineBuffer);//从文件中读取一行数据,将读到的数据写入lineBuffer
//
char c[40];
inFile.getline(c,40);
cout << c;
//
inFile.getline(c,40,'end');
cout << c;
//多行
while(inFile.getline(c,40))
{
cout << c <<endl;
}
4) 关闭文件
使用close()
关闭文件,确保所有资源被释放。
或,当ifstream
、ofstream
或fstream
对象被销毁时,它们的析构函数会关闭文件。
inFile.close();
outFile.close();
file.close();
5)错误处理
使用以下方法检查文件流的状态:
- good():无错误
- eof():到达文件末尾
- fail():非致命I/O错误
- bad():致命I/O错误
if (inFile.good())
{
// 继续处理文件
}
else if (inFile.eof())
{
cerr << "到达文件末尾" << endl;
}
else if (inFile.fail())
{
cerr << "非致命I/O错误" << endl;
}
else if (inFile.bad())
{
cerr << "致命I/O错误" << endl;
}
3.3 文件指针
可使用文件指针,移动文件内的读写位置:
- seekg:设置输入位置
- seekp:设置输出位置
- tellg:获取输入位置
- tellp:获取输出位置
// seekg和seekp:第一个参数指定位置,第二个参数指定查找方向
inFile.seekg(n); //定位到inFile的第n个字节(默认是ios::beg,即从流的开头开始定位)
inFile.seekg(n,ios::cur); //把文件的读指针从当前位置向后移n个字节
inFile.seekg(n,ios::end); //把文件的读指针从末尾往回移n个字节
inFile.seekg(0,ios::beg); //定位到文件开头
inFile.seekg(0,ios::end); //定位到文件末尾
// 获取文件大小
inFile.seekg(0,ios::end);
streampos size = inFile.tellg();
3.4 缓冲区
缓冲区类型:
- 全缓冲
- 当填满标准I/O缓存后,进行实际I/O操作。
- 典型代表:对磁盘文件的读写。
- 行缓冲
- 当在输入和输出中遇到换行符时,进行实际I/O操作。
- 此时,输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。
- 典型代表:键盘输入数据。
- 不带缓冲
- 不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。
C++之ofstream::flush与ofstream::close_ofstream flush-CSDN博客
3.5 跳过(忽略)指定字符
istream & ignore(int n =1, int delim = EOF);
跳过输入流中的 n 个字符,或跳过 delim 及其之前的所有字符,哪个条件先满足就按哪个执行。
两个参数都有默认值,因此 cin.ignore() 就等效于 cin.ignore(1, EOF), 即跳过一个字符。
int n;
cin.ignore(5, 'A');
cin >> n;
cout << n;
//cin.ignore() 跳过了输入中的前 5 个字符,其余内容被当作整数输入 n 中
abcde34↙
34
//cin.ignore() 跳过了输入中的 'A' 及其前面的字符,其余内容被当作整数输入 n 中
abA34↙
34