此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记使用。
1、文件操作-文件打开模式(方式)
如果文件不存在,各种模式都会创建文件。
ios::out 1)会截断文件;2)可以用seekp()移动文件指针。
ios:trunc 1)会截断文件;2)可以用seekp()移动文件指针。
ios::app 1)不会截断文件;2)文件指针始终在文件未尾,不能用seekp()移动文件指针。
ios::ate 打开文件时文件指针指向文件末尾,但是,可以在文件中的任何地方写数据。
ios::in 打开文件进行读操作,即读取文件中的数据。
ios::binary 打开文件为二进制文件,否则为文本文件。
注:ate是at end的缩写,trunc是truncate(截断)的缩写,app是append(追加)的缩写。
2、文件操作-随机存取
一、fstream类
fstream类既可以读文本/二进制文件,也可以写文本/二进制文件。
fstream类的缺省模式是ios::in | ios::out,如果文件不存在,则创建文件;但是,不会清空文件原有的内容。
普遍的做法是:
1)如果只想写入数据,用ofstream;如果只想读取数据,用ifstream;如果想写和读数据,用fstream,这种情况不多见。不同的类体现不同的语义。
2)在Linux平台下,文件的写和读有严格的权限控制。(需要的权限越少越好)
二、文件的位置指针
对文件进行读/写操作时,文件的位置指针指向当前文件读/写的位置。
很多资料用“文件读指针的位置”和“文件写指针的位置”,容易误导人。不管用哪个类操作文件,文件的位置指针只有一个。
1)获取文件位置指针
ofstream类的成员函数是tellp();ifstream类的成员函数是tellg();fstream类两个都有,效果相同。
std::streampos tellp();
std::streampos tellg();
2)移动文件位置指针
ofstream类的函数是seekp();ifstream类的函数是seekg();fstream类两个都有,效果相同。
方法一:
std::istream & seekg(std::streampos _Pos);
fin.seekg(128); // 把文件指针移到第128字节。
fin.seekp(128); // 把文件指针移到第128字节。
fin.seekg(ios::beg) // 把文件指针移动文件的开始。
fin.seekp(ios::end) // 把文件指针移动文件的结尾。
方法二:
std::istream & seekg(std::streamoff _Off,std::ios::seekdir _Way);
在ios中定义的枚举类型:
enum seek_dir {beg, cur, end}; // beg-文件的起始位置;cur-文件的当前位置;end-文件的结尾位置。
fin.seekg(30, ios::beg); // 从文件开始的位置往后移30字节。
fin.seekg(-5, ios::cur); // 从当前位置往前移5字节。
fin.seekg( 8, ios::cur); // 从当前位置往后移8字节。
fin.seekg(-10, ios::end); // 从文件结尾的位置往前移10字节。
三、随机存取
随机存取是指直接移动文件的位置指针,在指定位置读取/写入数据。
示例:
#include <iostream>
#include <fstream> // fstream类需要包含的头文件。
using namespace std;
int main()
{
string filename = R"(D:\data\txt\test.txt)";
fstream fs;
fs.open(filename, ios::in | ios::out);
if (fs.is_open() == false)
{
cout << "打开文件" << filename << "失败。\n"; return 0;
}
fs.seekg(26); // 把文件位置指针移动到第26字节处。
fs << "我是一只傻傻的小菜鸟。\n";
/*string buffer;
while (fs >> buffer)
{
cout << buffer << endl;
}*/
fs.close(); // 关闭文件,fs对象失效前会自动调用close()。
cout << "操作文件完成。\n";
}
3、文件操作-缓冲区及流状态
一、文件缓冲区
文件缓冲区(缓存)是系统预留的内存空间,用于存放输入或输出的数据。
根据输出和输入流,分为输出缓冲区和输入缓冲区。
注意,在C++中,每打开一个文件,系统就会为它分配缓冲区。不同的流,缓冲区是独立的。
程序员不用关心输入缓冲区,只关心输出缓冲区就行了。
在缺省模式下,输出缓冲区中的数据满了才把数据写入磁盘,但是,这种模式不一定能满足业务的需求。
输出缓冲区的操作:
1)flush()成员函数
刷新缓冲区,把缓冲区中的内容写入磁盘文件。
2)endl
换行,然后刷新缓冲区。
3)unitbuf
fout << unitbuf;
设置fout输出流,在每次操作之后自动刷新缓冲区。
4)nounitbuf
fout << nounitbuf;
设置fout输出流,让fout回到缺省的缓冲方式。
二、流状态
流状态有三个:eofbit、badbit和failbit,取值:1-设置;或0-清除。
当三个流状成都为0时,表示一切顺利,good()成员函数返回true。
1)eofbit
当输入流操作到达文件未尾时,将设置eofbit。
eof()成员函数检查流是否设置了eofbit。
2)badbit
无法诊断的失败破坏流时,将设置badbit。(例如:对输入流进行写入;磁盘没有剩余空间)。
bad()成员函数检查流是否设置了badbit。
3)failbit
当输入流操作未能读取预期的字符时,将设置failbit(非致命错误,可挽回,一般是软件错误,例如:想读取一个整数,但内容是一个字符串;文件到了未尾)I/O失败也可能设置failbit。
fail()成员函数检查流是否设置了failbit。
4)clear()成员函数清理流状态。
5)setstate()成员函数重置流状态。
示例1:
#include <iostream>
#include <fstream> // ofstream类需要包含的头文件。
#include <unistd.h>
using namespace std;
int main()
{
ofstream fout("/oracle/tmp/bbb.txt"); // 打开文件。
fout << unitbuf;
for (int ii = 0; ii < 1000; ii++) // 循环1000次。
{
fout << "ii=" << ii << ",我是一只傻傻傻傻傻傻傻傻傻傻傻傻傻傻的鸟。\n";
//fout.flush(); // 刷新缓冲区。
usleep(100000); // 睡眠十分之一秒。
}
fout.close(); // 关闭文件。
}
示例2:
#include <iostream>
#include <fstream> // ifstream类需要包含的头文件。
#include <string> // getline()函数需要包含的头文件。
using namespace std;
int main()
{
ifstream fin(R"(D:\data\txt\test.txt)", ios::in);
if (fin.is_open() == false) {
cout << "打开文件" << R"(D:\data\txt\test.txt)" << "失败。\n"; return 0;
}
string buffer;
/*while (fin >> buffer) {
cout << buffer << endl;
}*/
while (true) {
fin >> buffer;
cout << "eof()=" << fin.eof() << ",good() = " << fin.good() << ", bad() = " << fin.bad() << ", fail() = " << fin.fail() << endl;
if (fin.eof() == true) break;
cout << buffer << endl;
}
fin.close(); // 关闭文件,fin对象失效前会自动调用close()。
}