✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:C/C++知识点
📣专栏定位:整理一下 C++ 相关的知识点,供大家学习参考~
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
🎏唠叨唠叨:在这个专栏里我会整理一些琐碎的 C++ 知识点,方便大家作为字典查询~
文件操作
数据流的概念
数据流(data stream)是一组有序,有起点和终点的字节的数据序列。包括输入流和输出流。
c++通过一种称为流(stream)的机制提供了更为精良的输入和输出方法。流是一种灵活且面向对象的I/O方法。
根据操作对象不同分为文件流、字符串流、控制台流。
控制台流
C++输入输出操作分别是由istream(输入流)和ostream(输出流)这两个类提供的,为了允许双向的输入/输出,由istream和ostream派生出了iostream类。
类的继承关系如下图:
是一种多继承的关系,在程序应用可以只包含头文件iostream。
上面的<<和>>操作符,是因为iostream.h头文件中,ostream类对应每个基本数据类型都有其友元函数对左移操作符进行了友元函数的重载。
文件流
文件流的输入输出类在fstream头文件被定义,和控制台流继承关系为:
由于文件设备不像显示器屏幕和键盘那样标准的默认设备,所以我们定义一个流对象。
ofstream类的默认构造函数原形为:
ofstream::ofstream(constchar *filename,int mode = ios::out, int penprot = filebuf::openprot);
mode属性表:
打开文件属性值:
“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。文件使用完后可以使用close成员函数关闭文件。
ios::app为追加模式,在使用追加模式的时候同时进行文件状态的判断是一个比较好的习惯。
字符串流
字符串流就是能够控制字符串类型对象进行输入输出的类,C++不光可以支持C++风格的字符串流控制,还可以支持C风格的字符串流控制。
继承关系如下图:
类型 | 解释 |
---|---|
istrstream | C风格的串流的输入操作,字符串数组作为输入。 |
ostrstream | C风格的串流的输出操作,字符串数组作为输出。 |
strstream | 支持C风格的串流的输入输出操作。 |
文件处理简介
c++的文件处理也是看为一个对象,使用文件流的类,使用头文件,处理的时候有文本文件和二进制文件之分,主要的区别就是存储的形式。
C++ 通过以下几个类支持文件的输入输出:
- ofstream: 写操作(输出)的文件类 (由ostream引申而来)
- ifstream: 读操作(输入)的文件类(由istream引申而来)
- fstream: 可同时读写操作的文件类 (由iostream引申而来)
要在 C++ 中进行文件处理,必须在 C++ 源代码文件中包含头文件 <iostream>
和 <fstream>
。
文件处理基本流程:
文件的输入与输出
打开文件
在从文件读取信息或者向文件写入信息之前,必须先打开文件。
ofstream 和 fstream 对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream 对象。
下面是 open() 函数的标准语法,open() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
void open(const char *filename, ios::openmode mode);
open() 成员函数的第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。
可以把以上两种或两种以上的模式结合使用。例如,如果想要以写入模式打开文件,并希望截断文件,以防文件已存在,那么可以使用下面的语法:
ofstream outf;
outf.open("file.txt", ios::out | ios::trunc );
如果想要打开一个文件用于读写,可以使用下面的语法:
fstream file;
file.open("file.txt", ios::out | ios::in );
ofstream, ifstream 和 fstream所有这些类的成员函数open 都包含了一个默认打开文件的方式,这三个类的默认方式各不相同:
写入与读取
-
写入文件
在 C++ 编程中,可以使用流插入运算符( << )向文件写入信息,就像使用该运算符输出信息到屏幕上一样。唯一不同的是,在这里使用的是 ofstream 或 fstream 对象,而不是 cout 对象。
-
读取文件
在 C++ 编程中,可以使用流提取运算符( >> )从文件读取信息,就像使用该运算符从键盘输入信息一样。唯一不同的是,在这里使用的是 ifstream 或 fstream 对象,而不是 cin 对象。
关闭文件
当 C++ 程序终止时,它会自动关闭刷新所有流,释放所有分配的内存,并关闭所有打开的文件。但写程序时应该养成一个好习惯,在程序终止前关闭所有打开的文件。
下面是 close() 函数的标准语法,close() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
void close();
案例 - 写入
每次运行都会覆盖原来的内容:
#include <iostream>
#include <fstream> //1.头文件
using namespace std;
int main()
{
//2.创建流对象
ofstream outf;
//3.打开文件
outf.open("file.txt");
//outf.open("file.txt",ios::out);
//outf.open("file.txt",ios::app); //每次运行不会覆盖原来内容
//4.写入内容
outf << " 山村咏怀" << endl;
outf << " 邵雍" << endl;
outf << "一去二三里,烟村四五家。" << endl;
outf << "亭台六七座,八九十枝花。" << endl;
//5.关闭文件
outf.close();
return 0;
}
案例 - 读取
#include <iostream>
#include <fstream> //文件流的头文件
using namespace std;
int main()
{
//char cf[100]; //字符数组
string cf; //字符串
ifstream infile;
infile.open("file.txt",ios::in); //inf.open("file.txt");
infile >> cf;
infile.close();
cout << cf;
return 0;
}
在c++中使用ifstream读文件的时候会以空格为分隔符,遇到空格就不读取了。这时候可以调用get函数来读取内容。
#include <iostream>
#include <fstream> //文件流的头文件
using namespace std;
int main()
{
char a
ifstream infile; //定义ifstream类(输入文件流类)对象infile
infile.open("file.txt"); //打开文件 使文件流与c++.txt文件建立关联
while (!infile.eof())
{
infile.get(a); //依次获取文件中每个字符 并输出
cout << a;
}
infile.close();
return 0;
}
其实读取方式分为很多种,每种方式效率不同:
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main()
{
ifstream ifs;
ifs.open("file.txt", ios::in);
//判断是否打开
if (!ifs.is_open())
{
cout << "文件打开失败!" << endl;
return 0;
}
//读数据
//第一种:效率低,不建议使用
/*char c;
while ((c = ifs.get()) != EOF)
{
cout << c;
}*/
//第二种
/*char buf[1024] = {0};
while (ifs >> buf)
{
cout << buf << endl;
}*/
//第三种
/*char buf[1024] = {0};
while (ifs.getline(buf, sizeof(buf)))
{
cout << buf << endl;
}*/
//第四种
string buf;
while (getline(ifs,buf)) //getline函数需要#include <string>
{
cout<<buf<<endl;
}
ifs.close();
return 0;
}
二进制文件读写
写文件
二进制写文件主要利用流对象调用成员函数 write()
函数原型:
ostream& write(const char*buffer,int len);
参数解释:字符指针buffer指向内存中的一段存储空间,len是读写的字节数
案例:
#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()
函数原型:
istream& read( char*buffer,int len);
参数解释:字符指针buffer指向内存中的一段存储空间,len是读写的字节数
案例:
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文件操作
ifstream支持>>操作,ofstream支持<<操作,fstream同时支持>>和<<操作。
打开文件 fstream可以在声明流对象时传入文件名打开文件,也可以使用open()函数打开文件。
关闭文件 文件打开后必须关闭,fstream提供close()函数关闭文件。
打开文件
使用构造函数声明对象时打开文件,示例:
fstream file(filename, ios::in | ios::out);
使用open()函数打开文件,函数原型:
void open(const char* filename,int mode,int access);
如果只传入文件名,系统会自动根据文件类型选择默认的打开模式。
打开文件模式mode如图:
模式和属性可以单独使用,也可以混合使用。混合使用时,用逻辑连接符或 |连接。
ios::out模式默认会清空,即ios::out|ios::trunc和ios::out打开文件时都会清空文件。
如果不想清空文件,那么设置读写模式为ios::out|ios::app,以这种模式打开文件后,数据会以追加的方式写入到文件。
读写文件
fstream提供的读写操作有:<<、>>、read()、write()、put()、get()、getline()。根据文件类型可分为文本文件和二进制文件,根据读写方式可分为逐行读写和整块读写。通常,文本文件使用逐行读写的方式,二进制文件使用整块读写的方式。
-
文本文件读写
逐行写入文本文件可以使用操作符====<<。
逐行读取文本文件时可以使用==getline()==函数。
-
二进制文件的读写
二进制文件通常整块读取或写入,当然也可以读写单个字符,用到的函数包括:put()、get()、read()、write()。
通常使用write()、put()函数写入二进制文件。使用read()、get()读取二进制文件。
案例
#include <iostream>
#include <fstream> //1.包含头文件
#include <string>
using namespace std;
int main()
{
string str;
fstream iofile; //2.创建对象
iofile.open("file.txt",ios::out|ios::in|ios::trunc); //3.打开文件
iofile << "这里是写入内容测试" << endl; //4.写入数据
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;
}
文件定位和大小
C++的文件定位分为读位置和写位置的定位,对应的成员函数分别为seekg()和seekp()。seekg()函数设置读位置,seekp()设置写位置。函数原型如下:
istream& seekg(streamoff offset,seek_dir origin);
ofstream& seekp(streamoff offset,seek_dir origin);
offset表示偏移量,seek_dir表示移动的基准位置,取值如下:
取值 | 解释 |
---|---|
ios::beg | 文件开头 |
ios::cur | 文件当前位置 |
ios::end | 文件结尾 |
示例:
inFile.seekg(2,ios::beg); // 把文件读指针从开始位置向后移动2个字节
outFile.seekp(2,ios::cur); // 把文件写指针从当前位置向后移动2个字节
获取文件大小可以使用seekg()和tellg()或者seekp()和tellp()函数结合使用的方式获取文件大小。
示例:
inFile.seekg(0,ios::end); // 读文件指针移动到文件末尾
streampos ipos = inFile.tellg(); //返回当前指针的位置,也就是文件的大小,单位是字节
由此,我们可以对文件大小进行计算:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
long start, end;
ifstream ifile;
ifile.open("test.txt", ios::in | ios::binary);
start = ifile.tellg();
ifile.seekg(0, ios::end);
end = ifile.tellg();
ifile.close();
cout << (end - start) << " bytes.\n"; //文件字节大小
return 0;
}