《C++》基础入门_16——输入输出流详讲

以下内容为大学期间学习C++语言总结的知识:

《C++》基础入门_01——数据存储,表示形式,基本运算
《C++》基础入门_02——面向对象的总体概括
《C++》基础入门_03——程序的开发过程
《C++》基础入门_04——四大语句
《C++》基础入门_05——函数详解篇
《C++》基础入门_06——面向对象的详述
《C++》基础入门_07——数据的共享保护:const
《C++》基础入门_08——利用数组实现对批量数据的处理
《C++》基础入门_09——指针和引用的讲解
《C++》基础入门_10——用户自定义数据类型详细篇
《C++》基础入门_11——友元的讲解
《C++》基础入门_12——类模板
《C++》基础入门_13——运算符的重载
《C++》基础入门_14——继承与派生
《C++》基础入门_15——多态性
《C++》基础入门_16——输入输出流详讲
《C++》基础入门_17——对象串行化
《C++》基础入门_18——异常处理
《C++》基础入门_19——命名空间
《C++》基础入门_20——文件操作
《C++》基础入门_21——在函数中返回数组的常用方法


文章目录

    • 一、输入输出的含义
    • 二、c++的输出输入流
    • 三、c++的流库
      • 3.1 与流类库有关的头文件
      • 3.2 iostream头文件中定义的流对象
    • 四、标准输出流
    • 五、标准输入流
      • 5.1 cin流
      • 5.2 提取运算符(>>)
      • 5.3 用于字符输入的流成员函数
      • 5.4 istream类的其他成员函数
    • 六、对数据文件的操作与文件流
      • 6.1 文件概念
      • 6.2 文件流类
        • 6.2.1 文件的打开和关闭
    • 七、对ASCII文件的操作
    • 八、对二进制文件的读取
    • 九、字符串流
      • 9.1 字符流类
      • 9.2 建立输出字符流对象
      • 9.3 建立输入字符流对象
      • 9.4 建立输入输出字符串流对象
    • 十、宽字符,宽字符串,宽流
      • 10.1 宽字符:wchar_t类型
      • 10.2 宽字符串:wstring 类型
      • 10.3 宽流:以宽字符为基本单位的流
      • 10.4 为宽文件流配置编码方案
      • 10.5 locale


一、输入输出的含义

  • 从操作系统角度来看,每一个与主机相连的输入输出设备都看作一个文件。
  • 程序的输入指的是从输入文件将数据传送到程序;
    程序的输出指的是从程序将数据传送给输出文件。
  • c++通过类对象实现输入输出—cin和cout。
    c通过函数实现输入输出—scanf和printf.
  • C++输入输出包括3个方面:
    1. 对系统指定的标准设备的输入输出。即从键盘输入数据,输出到显示屏。这种输入输出称为标准的输入输出,简称标准I/O.
    2. 以外存(磁盘,光盘)为对象进行输入输出。这种以外存文件为对象的输出输入称为文件的输入输出,简称文件I/O。
    3. 对内存中指定的空间进行输出输入。通常指定一个字符数组作为存储空间。称为字符串输入输出,简称串I/O。

二、c++的输出输入流

  • 输入输出是数据传送的过程。c++把这个过程称为流。流表示信息从源到目的端的流动。
  • c++输入输出流是指由若干个字节组成的字节序列,这些字节中的数据按顺序从一个对象传送到另一个对象。
  • 流中的内容可以是ASCII字符,二进制形式的数据,图形图像,数字音频视频或其他形式的信息。
  • 在内存中为每一个数据流开辟了一个内存缓存区,用来存放流中的数据。当用cout和“<<”向显示屏输入信息时,先将这些数据插入到输出流(cout流)。送到程序中的输出缓存区保存,直到缓存区满或遇到“endl”,就将缓冲区中的全部数据送到显示器显示出来。当输入数据时,从键盘输入的数据先放入键盘缓存区,当按回车键时,键盘缓冲区中的数据输入到程序中的输入缓存区,形成cin流,然后用提取“>>”运算符从缓冲区中提取数据传送到程序中的有关变量。缓存区中的数据就是流。
  • 当程序与外界环境进行信息交换时,存在着两个对象,一个是程序中的对象,另一个是文件对象。
  • 流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动。
  • 程序建立一个流对象,并指定这个流对象与某个文件对象建立连接,程序操作流对象,流对象通过文件系统对所连接的文件对象产生作用。
  • 读操作在流数据抽象中被称为(从流中)提取,写操作被称为(向流中)插入。
  • C++中,输入输出流被定义为类。C++的I/O库中的类称为流类。用流类定义的对象为流对象。

三、c++的流库

c++提供了一些类,专门用于输出输入。这些类组成一个流类库,简称流库。
流类库是采用继承方式建立的,这些类的两个基类:ios类和streambuf类,所有其他流类都是从他们直接或间接派生出来的。
《C++》基础入门_16——输入输出流详讲_第1张图片

3.1 与流类库有关的头文件

iostream 包含了对输入输出流进行操作所需的基本信息
fstream 用于用户管理的文件的I/O操作
strstream 用于字符串流
iomanip 在使用格式化I/O时应包含此头文件
stdiostream 用于混合使用c++和c的I/O时

3.2 iostream头文件中定义的流对象

《C++》基础入门_16——输入输出流详讲_第2张图片

四、标准输出流

  • 最重要的三个输出流是

    1. ostream(标准输出流)
    2. ofstream
    3. ostringstream
  • ostream类提供了数据流输出的功能,其流对象是流的目的地。在程序里可以将数据不断地插入流中,送至这些ostream流对象。

  • 输出时使用的ostream流对象通常是cout,有3种基本操作方式:

    1. 是用流插入运算符,输出基本类型的数据;
    2. 是用成员函数put,输出一个字符;
    3. 是用成员函数write,输出一个字符串 。
  • ostream定义的三个输出流对象

    1. cout 标准输出
    2. cerr 标准错误输出,没有缓冲,发送给它的内容立即被输出。数据只能传送到显示器显示。
    3. clog 类似于cerr,但是有缓冲,缓冲区满或遇到“endl”时被输出。
  • 插入运算符(<<)

    1. 插入(<<)运算符是所有标准C++数据类型预先设计的。
    2. 用于传送字节到一个输出流对象。
  • 用流对象的成员函数控制输出格式
    1. 用于控制输出格式的流成员函数

    《C++》基础入门_16——输入输出流详讲_第3张图片

    使用width控制输出宽度

    #include 
    using namespace std;
    int main() {
    	double values[] = { 1.23, 35.36, 653.7,	4358.24 };
    	for (int i = 0; i < 4; i++) {
    		cout.width(10);
    		cout << values[i] << endl;
    	}
    	return 0;
    }
    

    《C++》基础入门_16——输入输出流详讲_第4张图片

    使用*填充

    #include 
    using namespace std;
    int main() {
    	double values[] = { 1.23, 35.36, 653.7, 4358.24};
    	for (int i = 0; i < 4; i++) {
    		cout.width(10);
    		cout.fill('*');
    		cout << values[i] << '\n';
    	}
    	return 0;
    }
    

    《C++》基础入门_16——输入输出流详讲_第5张图片

    使用setw指定宽度和对齐方式和控制输出精度

    #include 
    #include 
    #include 
    using namespace std;
    int main() {
    	double values[] = { 1.23, 35.36, 653.7, 4358.24};
    	string names[] = { "Zoot", "Jimmy", "Al", "Stan"};
    	for (int i = 0; i < 4; i++)
    		cout << setw(6) << names[i]<< setw(10) << values[i] << endl;
    
        cout << endl;
        cout << endl;
    
         //设置对齐方式
    	for (int i = 0; i < 4; i++)
    		cout << setiosflags(ios_base::left)
    		<< setw(6) << names[i]
    		<< resetiosflags(ios_base::right)
    		<< setw(10) << values[i] << endl;
    	
    	cout << endl;
        cout << endl;
        //控制输出精度
     	for (int i = 0; i < 4; i++)
    		cout << setiosflags(ios_base::left)
    		<< setw(6) << names[i]
    		<< resetiosflags(ios_base::left)
    		<< setw(10) << setprecision(1) << values[i]
    		<< endl;	
    		return 0;
    }
    

    《C++》基础入门_16——输入输出流详讲_第6张图片

  1. 设置格式状态的格式标志

    格式标志 作用
    ios::left 输出数据在本域宽范围内向左对齐
    os::right 输出数据在本域宽范围内向右对齐
    os::internal 数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充
    ios::dec 设置整数的基数为10
    os::oct 设置整数的基数为8
    os::hex 设置整数的基数为16
    ios::showbase 强制输出整数的基数(八进制数以0打头,十六进制数以0x打头)
    os::showpoint 强制输出浮点数的小点和尾数0
    os::uppercase 在以科学记数法格式E和以十六进制输出字母时以大写表示
    ios::showpos 对正数显示“+”号
    ios::scientific 浮点数以科学记数法格式输出
    os::fixed 浮点数以定点格式(小数形式)输出
    ios::unitbuf 每次输出之后刷新所有的流
    os::stdio 每次输出之后清除stdout, stderr
    	#include 
    	#include
    	using namespace std;
    	int main( ){ 
    		int a = 21;
    		cout.setf(ios::showbase);      //显示基数符号(0x或)   
    		cout<<"dec:"<<a<<endl;         //默认以十进制形式输出a   
    		cout.unsetf(ios::dec);         //终止十进制的格式设置   
    		cout.setf(ios::hex);           //设置以十六进制输出的状态   
    		cout<<"hex:"<<a<<endl;         //以十六进制形式输出a   
    		cout.unsetf(ios::hex);         //终止十六进制的格式设置   
    		cout.setf(ios::oct);           //设置以八进制输出的状态   
    		cout<<"oct:"<<a<<endl;         //以八进制形式输出a    
    		const char *pt="China";              //pt指向字符串"China"   
    		cout.width(10);                //指定域宽为   
    		cout<<pt<<endl;                //输出字符串   
    		cout.width(10);                //指定域宽为   
    		cout.fill('*');                //指定空白处以'*'填充   
    		cout<<pt<<endl;                //输出字符串   
    		double pi=22.0/7.0;            //输出pi值   
    		cout.setf(ios::scientific);    //指定用科学记数法输出   
    		cout<<"pi=";                   //输出"pi="   
    		cout.width(14);                //指定域宽为   
    		cout<<pi<<endl;                //输出pi值   
    		cout.unsetf(ios::scientific); //终止科学记数法状态   
    		cout.setf(ios::fixed);        //指定用定点形式输出   
    		cout.width(12);               //指定域宽为   
    		cout.setf(ios::showpos);      //正数输出“+”号   
    		cout.setf(ios::internal);     //数符出现在左侧   
    		cout.precision(6);            //保留位小数   
    		cout<<pi<<endl;               //输出pi,注意数符“+”的位置   
    		return 0;
    	}
    

    《C++》基础入门_16——输入输出流详讲_第7张图片

    	#include 
    	#include 
    	#include 
    	using namespace std;
    	int main() {
    		double values[] = { 1.23, 35.36, 653.7, 4358.24 };
    		string names[] = { "Zoot", "Jimmy", "Al", "Stan" };
    		for (int i = 0; i < 4; i++)
    			cout << setiosflags(ios_base::left)
    			<< setw(6) << names[i]
    			<< resetiosflags(ios_base::right)
    			<< setw(10) << values[i] << endl;
    		return 0;
    		/*
    		Zoot  1.23
    		Jimmy 35.36
    		Al    653.7
    		Stan  4358.24
    		*/
    	} 
    	```
    
    >
    
  • 流成员函数put输出字符
    专用于输出一个字符的成员函数。
    putchar也可以实现和put相同功能,它是c语言提供的方法,在stdio.h头文件中定义。
    #include
    #include
    using namespace std;
    int main() {
    	const char *p = "I am a good girl";
    	for (int i = 0; i < 10; i++)
    		cout.put(*(p + i));
    	cout.put('\n');
    	cout.put(65 + 32);//输出ASCII对应的字符
    	return 0;
    	/*
    	I am a goo
    	a
    	*/
    }
    
    

五、标准输入流

  • 重要的输入流类:
    1. istream类最适合用于顺序文本模式输入。
    2. ifstream类支持磁盘文件输入。
    3. istringstream

5.1 cin流

  • istream类的派生类的对象,它从标准输入设备获取数据,程序里的变量通过“>>”从流中提取数据。
  • 通常跳过输入流中的空格,tab键,回车键等空白符。
  • 一般用Ctrl+z或者Ctrl+D表示文件的结束。
  • 遇到无效字符和文件结束符时,cin处于出错状态。它的值为0(false)。

if(!cin) cout<<“error”;

5.2 提取运算符(>>)

  • 提取运算符(>>)对于所有标准C++数据类型都是预先设计好的。
  • 是从一个输入流对象获取字节最容易的方法。
  • ios类中的很多操纵符都可以应用于输入流。但是只有少数几个对输入流对象具有实际影响,其中最重要的是进制操纵符dec、oct和hex。

5.3 用于字符输入的流成员函数

  • get函数读入一个字符
    get函数有三种形式:
    1. 无参,
      调用形式:cin.get();
      用于从指定的输入流提取一个字符,包括空白字符,函数返回值为读到的字符。若遇到文件结束符,返回EOF(-1)。
      c语言中对应的有getchar();

      
      		#include 
      		#include 
      		#include 
      		using namespace std;
      		int main() {
      			int c;
      			cout << "enter a sentence:" << endl;
      			while ((c = cin.get()) != EOF)
      				cout.put(c);
      			return 0;
      			/*
      			enter a sentence:
      			i sds  sdsds  we
      			i sds  sdsds  we
      			*/
      		}
      
      
    2. 一个参
      调用形式:cin.get(ch);
      用于从指定的输入流提取一个字符,赋给字符变量ch。读取成功,返回非零值,否则返回0。

    3. 三个参数
      调用形式:
      cin.get(字符数组,字符个数,终止字符);
      cin.get(字符指针,字符个数,终止字符);
      用于从指定的输入流提取n-1个字符,赋给数组或指针。读取到设定的终止字符·处。读取成功,返回非零值,否则返回0。

  • 成员函数getline读入一行字符
    作用:用于从输入流提取一行字符,赋给数组或指针。读取到设定的终止字符·处。读取成功,返回非零值,否则返回0。
    形式:
    cin.getline(字符数组,字符个数n,终止字符);
    cin.getline (字符指针,字符个数n,终止字符);

    cin.getline(ch,20,’/’):读入19个字符或者遇到‘/’结束,在最后一位加‘/0’,存入数组或指针ch中

5.4 istream类的其他成员函数

  • eof函数

    1. 表示文件结束。

    2. 从输入流中读取数据,如果到达文件末尾(遇到文件结束符),eof函数值为非0值,否则为0(假)。

       	int c;
      	cout << "enter a sentence:" << endl;
      	while (!cin.eof())
      		if((c=cin.get())!=' ')//检查输入字符是否为空格字符
      		cout.put(c);
      
  • peek函数

    1. 作用:是观察的意思,是观察下一个字符。
    2. 调用形式:
      c=cin.peek();
    3. 返回值是指针指向的当前字符的下一个字符的值,但它是观测,指针任然保留在当前位置,并不后移,文件结束符返回eof(-1)。
  • putback函数

    1. 调用形式:
      cin.putback(ch);
    2. 作用:将前面用get和getline读到的字符ch返回输入流。插入到当前指针位置,以供后面读取。
    #include 
    #include 
    #include 
    using namespace std;
    int main() {
    	char c[20];
    	int ch;
    	cout << "enter a sentence:" << endl;
    	cin.getline(c, 15, '/');
    	cout << "first part:" << c << endl;
    	ch = cin.peek();
    	cout << "the next char is:" << ch << endl;
    	cin.putback(c[0]);
    	cin.getline(c, 15, '/');
    	cout << "second part:" << c << endl;
    	
    	return 0;
    

    《C++》基础入门_16——输入输出流详讲_第8张图片

  • ignore函数

  1. 调用形式:
    cin.ignore(n,终止符);
    可以不带或者带一个参数。
  2. 作用:跳过输入流中n个字符,或遇到指定的终止符时提前结束(此时跳过包含终止符在内的若干字符)。
  3. n默认为1,终止符默认为eof。
#include 
#include 
#include 
using namespace std;
int main() {
	char c[20];
	cout << "enter a sentence:" << endl;
	cin.get(c, 20, '/');
	cout << "first part:" << c << endl;
	cin.ignore();//若不加此函数,next patr 无法取到值,因为当前指针停在/处
	cin.get(c, 20, '/');
	cout << "the next part:" << c<< endl;
	return 0;
	/*
	enter a sentence:
	i like c++./l study c++./i am unhappy.
	first part:i like c++.
	the next part:l study c++.
	*/
}




六、对数据文件的操作与文件流

6.1 文件概念

  • 文件原理: 文件打开都有一个文件指针,该指针的初始位置由I/O方式指定,每次读写都从文件指针的当前位置开始。每读入一个字节,指针就后移一个字节。当文件指针移到最后,就会遇到文件结束EOF(文件结束符也占一个字节,其值为-1),此时流对象的成员函数eof的值为非0值(一般设为1),表示文件结束 了。

  • 文件是程序的一个重要部分。文件一般是存储在外部介质上数据的集合。

  • 操作系统以文件为单位对数据进行管理。

  • 常见文件分类:

    1. 程序文件
      源程序文件(.cpp),目标文件(.obj),可执行文件(.exe)。
    2. 数据文件
      在程序运行时,常常需要将一些数据输出到磁盘上存放起来,以后需要时在读取到计算机内存。
  • 根据文件中数据的组织形式:

    1. ASCII文件
      文本文件或字符文件,每一个字节放一个ASCII代码。
    2. 二进制文件
      字节文件,把内存中的数据按照在内存中的存储形式原样输出在磁盘上存放.
       1. 对于字符来说,在内存中以ASCII码存放,每一个字节放一个ASCII代码,因此无论用ASCII文件输出还是二进制文件输出,其数据形式一样。
       2. 对于数值数据,二者不同。
        比如:整数100000,在内存中占有4个字节,若按内部格式直接输出,在磁盘中占有4个字节,但是转换成ACSII形式输出,6个字符占有6个字节。
      

      在这里插入图片描述

    c++提供了二种I/O:

    1. 高级I/O:
      把若干个字节组合为一个有意义的单位,然后以ASCII字符形式输入输出。

      例如将内存中的数据送到显示器上输出,先把内存中的数据转换成ASCII字符,然后按照整型,浮点型等形式输出。

    2. 低级I/O:
      以字节为单位输入输出,在输入输出过程中不进行格式的转换。是以二进制形式进行的。通常用于在内存和设备之间传输一些字节。

6.2 文件流类

  • c++中的cin和cout只能处理标准设备为对象的输入输出,而不能处理以磁盘文件为对象的输出输入。必须另外定义以磁盘文件为对象的输入输出。
  • 文件流:以外存文件为输入输出对象的数据流。
    输出文件流是从内存流向外存文件的数据,
    输入文件流是从外存文件流向内存的数据。
    每一个文件流都有一个内存缓存区与之对应。
  • 文件流本身不是文件,而是以文件为输入输出对象的流。对磁盘文件的读取必须通过·文件流实现。
  • 以磁盘文件为对象的输入输出,必须定义文件流对象。文件流对象是文件流类定义的,而不是iostream定义的。

用于文件操作的文件类:

  1. ifstream类,从istream类派生的。用于支持从磁盘文件的输入。
  2. ofstream类,从ostream类派生的。用于支持从磁盘文件的输出。
  3. fstream类,从iostream类派生的。用于支持从此磁盘文件的输入输出。

6.2.1 文件的打开和关闭

  • 文件输入输出方式设置值
    在这里插入图片描述
    a. 新版本I/O不提供iOS:nocreate和ios::noreplace.
    b. 可以用位或运算符“|”进行输入输出方式的组合。
  • 打开磁盘文件
    打开文件是指在文件读写前做好准备工作:
    1. 为文件流对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件。
    2. 指定文件的工作方式。是输出还是输入,操作的是二进制文件还是ASCII文件。

以上工作通过二种方式实现:

  1. 调用文件流的成员函数open。
    一般调用方式:
    文件流对象.open(磁盘文件名,输入输出方式);
    磁盘文件名可以包含路径,若缺省则默认当前目录下的文件。
    若打开失败则open函数返回值为0.

    例如:
    ofstream outfile; //建立一个文件输出类对象
    outfile.open(“f1.dat”,ios::out); //使文件流与f1.dat建立联系
    outfile.open(“C:\c++\f1.dat”,iso::out);
    iso::out:是I/O的一种,表示以输出方式打开文件。

  2. 在定义文件流对象时指定参数
    声明文件流对象时定义了带参数的构造函数,其中包括打开文件的功能。
    调用形式:
    文件流类 文件流对象名(“文件路径”,输入输出方式)
    若打开失败,流对象返回值为0。

    例如:
    ostream outfile(“f1.dat”,ios::out);

  • 关闭磁盘文件
    1. 调用成员函数,解除关联。
      文件流对象名.close();
    2. 解除当前文件关联,建立与其他文件的关联。
      文件流对象名.close(“新关联文件路径”,输入输出方式);

七、对ASCII文件的操作

文件的每个字节都以ACSII形式存放,此文件为ASCII文件。
对ASCII读写操作有两种:

  1. 用流插入运算符“<<”和流提取“>>"运算符输入输出标准类型的数据。
    由于ofstream和ifstream从ostream和istream类继承了公用的重载函数,所以对磁盘文件的操作,可以通过文件流对象和流插入,流提取运算符对文件进行读写。

    写入文件内容:

    #include 
    #include 
    using namespace std;
    int main() {
    	int a[10];
    	ofstream outfile("f1.dat", ios::out);   //定义文件流对象,打开磁盘文件f1.dat
    	if (!outfile) {                         //若打开失败,返回0
    		cerr << "open error!" << endl;
    		exit(1);
    	}
    	cout << "please enter 10 integer number:" << endl;
    	for (int i = 0; i < 10; i++) {
    		cin >> a[i];
    		outfile << a[i] << " ";            //将键盘输入的数据输出到磁盘文件
    	}
    	outfile.close();                       //关闭文件流
    	return 0;
    

    文件建立在了当前程序存放空间下的地方。若不存在此文件,会新建一个f1.dat文件,若存在,则直接打开此文件并覆盖其内容。
    《C++》基础入门_16——输入输出流详讲_第9张图片

    读取文件内容

    #include 
    #include 
    using namespace std;
    int main() {
    	int a[10];
    	ifstream infile("f1.dat",ios::in|ios::_Nocreate);    //定义文件流对象,以输入方式打开磁盘文件f1.dat若不存在也不会新建此文件。
    	if (!infile) {
    		cerr << "open error!" << endl;
    		exit(1);
    	}
    	for (int i = 0; i < 10; i++) {
    		infile>> a[i];      //从磁盘读取10个字符,顺序存放在数组中。
    		cout << a[i]<<" ";
    	}
    	cout << endl;
    	infile.close();
    	return 0;
    }
    

    《C++》基础入门_16——输入输出流详讲_第10张图片

  2. 用文件流的put,get,getline等成员函数进行字符的输入输出。

    #include 
    #include 
    using namespace std;
    //此函数从键盘读取一行字符并把字母存入磁盘文件
    void save_to_file() {
    	ofstream outfile("f2.txt", ios::out);//定义输出流文件对象,以输出方式打开磁盘文件f2
    	if (!outfile) {
    		cerr << "open error!"<<endl;
    		exit(1);
    	}
    	char c[100];
    	cin.getline(c, 100);   //从键盘上读取一行字符
    	for (int i = 0; c[i] != 0; i++) {
    		if (c[i] >= 65 && c[i] <= 90 || c[i] >= 97 && c[i] <= 122) {//判断是否为字母
    			outfile.put(c[i]);//若为字母保存在文件f2中
    			cout << c[i];     //并显示在屏幕上
    		}
    	}
    	cout << endl;
    	outfile.close();
    }
    //此函数读取文件中所以字母,并把所以小写字母转化为大写字母,全部存入f3文件中
    void get_from_file() {
    	char ch;
    	ifstream infile("f2.txt", ios::in | ios::_Nocreate);
    	if (!infile) {
    		cerr << "open f2.txt  error!" << endl;
    		exit(1);
    	}
    	ofstream outfile("f3.txt", ios::out);
    	if (!outfile) {
    		cerr << "open f3.txt error!" << endl;
    		exit(1);
    	}
    	while (infile.get(ch)) {//从磁盘文件读取字符,直到文件结束
    		if (ch >= 97 && ch <= 122)
    			ch -= 32;
    			outfile.put(ch);//读取的单个字符存入f3文件
    			cout << ch;
    	}
    		cout << endl;
    		infile.close();
    		outfile.close();
    }
    //读取磁盘文件内容
    void display_file(string s) {
    	ifstream infile(s,ios::in);
    	if (!infile) {
    		cerr << "open error" << endl;
    		exit(1);
    	}
    	char ch;
    	while (infile.get(ch))
    		cout.put(ch);
    	cout << endl;
    	infile.close();
    }
    int main() {
    	save_to_file();
    	get_from_file();
    	display_file("f3.txt");
    	return 0;
    }
    

    《C++》基础入门_16——输入输出流详讲_第11张图片

  • ofstream流对象:
    ofstream 类支持磁盘文件输出
    1. 如果在构造函数中指定一个文件名,当构造这个文件时该文件是自动打开的
      ofstream myFile (“filename”);
    2. 可以在调用默认构造函数之后使用 open 成员函数打开文件
      ofstream myFile ; // 声明一个静态文件输出流对象
      myFile.open (“filename”);// 打开文件,使流对象与文件建立联系
    3. 在构造对象或用 open 打开文件时可以指定模式
      ofstream myFile (“filename”, ofstream myFile (“filename”,ios_base ::out | ios_base ::binary);



八、对二进制文件的读取

  • 二进制文件将内存中数据存储行式不加转换的存入磁盘文件。称为内存文件的印像文件。内存中数据二进制形式存放,又称字节文件。
  • 读取前的操作:先打开文件,打开时要用iOS::binary指定为以二进制形式传送和存储。二进制文件可以作即输入又输出的文件。这点和ASCII文件不同。
  1. 用成员函数read和write读写二进制文件
    对二进制文件的读写主要用istream类的成员函数read和write来实现
    istream& read(char *buffer,int len);
    ostream& write(const char * buffer,int len);

    • read函数的功能是从输入流中顺序读取len个字符,并存入到buffer所指向的字
      符数组中。它与get函数、getline函数的区别是,不在读取的这些字符的尾部添加一个空字符(’\0’)。
      存二进制文件

      #include 
      #include 
      using namespace std;
      struct Student {
      	char name[20];
      	int age;
      	char sex;
      };
      int main() {
      	Student stu[3] = { {"Tom",18,'f' },{"Sun",17,'f'},{"Rain",13,'f'} };
      	ofstream outfile("student.dat", ios::binary);
      	if (!outfile) {
      		cerr << "open error " << endl;
      		abort();
      	}
      	//此处if语句可以改写成write.((char*)&stu[0],sizeof(stu));
      	for (int i = 0; i < 3; i++) {
      		outfile.write((char *)&stu[i], sizeof(stu[i]));
      	}
      	outfile.close();
      	return 0;
      }
      

      在这里插入图片描述

      读取二进制文件

      #include 
      #include 
      using namespace std;
      struct Student {
      	char name[20];
      	int age;
      	char sex;
      };
      int main() {
      	Student stu[3];
      	ifstream infile("student.dat", ios::binary);
      	if (!infile) {
      		cerr << "open error " << endl;
      		abort();
      	}
      	for (int i = 0; i < 3; i++) {
      		infile.read((char *)&stu[i], sizeof(stu[i]));
      	}
      	infile.close();
      	for (int i=0; i < 3; i++) {
      		cout << stu[i].name << " " << stu[i].age << " " << stu[i].sex << endl;
      	}
      	return 0;
      	/*
      	Tom 18 f
      	Sun 17 f
      	Rain 13 f
      
      	*/
      }
      
  2. 以文件指针有关的流成员函数

    • 在磁盘文件中有一个文件读写位置标记来指定当前应进行读写的位置。在从文件输入时每读入一个字节,该位置就往后移动一个字节,该位置就向后移动一个字节。在输出时每向文件输出一个字节,位置标记也向后移动一个字节,随着输出文件中字节不断增加,位置不断后移。
    • 对于一个二进制文件,允许对位置标记进行控制,使它按照用户的意图移动到所需的位置,以便在该位置上读写。
    • 文件流与文件位置标记有关的成员函数
    员函数 作用
    gcount() 得到最后一次输入所读入的字节数
    ellg() 得到输入文件位置标记的当前位置
    ellp() 得到输出文件位置标记当前的位置
    eekg(文件中的位置) 将输入文件位置标记移到指定的位置
    eekg(位移量,参照位置) 以参照位置为基础移动若干字节
    eekp(文件中的位置) 将输出文件位置标记移到指定的位置
    eekp(位移量,参照位置)) 以参照位置为基础移动若干字节

    参照位置

    ios::beg 文件开头(默认)
    ios::cur 位置标记当前的位置
    os::end 文件的末尾

    infile.seekg(100): 输入文件位置标记向前移到100字节位置
    infile.seekg(-50,ios::cur):输入文件位置标记从当前位置后移50字节
    infile.seekg(-50,ios::end):输入文件位置标记从文件尾后移50字节

  3. 随机访问二进制数据文件
    一般文件的读写时顺序进行的,逐个字节读写。但是对于二进制文件来说,可用成员函数移动指针,随机访问任意位置的数据,还可以修改文件中的数据。

    #include 
    #include 
    using namespace std;
    struct Student {
    	char name[20];
    	int age;
    };
    int main() {
    	Student stu[5] = {"A",12,"df",23,"wq",21,"sds",32,"ed",23};
    	fstream iofile("student.dat",ios::in|ios::out|ios::binary);
    	if (!iofile) {
    		cerr << "open error " << endl;
    		abort();
    	}
    	for (int i = 0; i < 5; i++) {
    		iofile.write((char*)&stu[i], sizeof(stu[i]));
    	}
    	Student stu1[5];
    	for(int i=0;i<5;i+=2){
            iofile.seekg(i*sizeof(stu[i]),ios::beg);//定位于0,2,4学生数据开头
    		iofile.read((char*)&stu1[i / 2], sizeof(stu1[0]));//先后读入三个学生的数据,存入stu1[0],stu1[1],stu1[2]
    		cout << stu1[i/2].name << "   " << stu1[i/2].age << endl;
    	}
    	cout << endl;
    	strcpy_s(stu[2].name, "yj");
    	stu[2].age = 18;
    	iofile.seekp(2 * sizeof(stu[0]), ios::beg);//定位第3个学生数据开始处
    	iofile.write((char*) &stu[2], sizeof(stu[2]));//更新第3个学生数据
    	iofile.seekg(0, ios::beg);
    	for (int i = 0; i < 5; i++) {
    	   iofile.read((char*)&stu[i], sizeof(stu[i]));
    	   cout << stu[i].name << "   " << stu[i].age << endl;
        }
    	iofile.close();
    	return 0;
    	/*
            A   12
    		wq   21
    		ed   23
    
    		A   12
    		df   23
    		yj   18
    		sds   32
    		ed   23
    
    	*/
    }
    

举例:

#include 
#include 
using namespace std;
#include 

class Teacher
{
public:
	Teacher() {}
	Teacher(int sno, const char name[]){
		this->sno= sno;
		strcpy_s(this->name, name);
	}
	void prinf(){
		cout << "Teacher name:" << this->name << "   sno:" << this->sno << endl;
	}
private:
	int sno;
	char name[20];
};

int main()
{
	Teacher t1( 1001 ,"Tom");
	Teacher t2( 1002 , "Rain");
	Teacher t3( 1003 , "Sun");
	Teacher t4( 1004 , "Jain");
	fstream fs("teacher", ios::binary | ios::out);
	if (!fs)
	{
		cout << "文件打开失败" << endl;
	}
	fs.write((char *)&t1, sizeof(Teacher));
	fs.write((char *)&t2, sizeof(Teacher));
	fs.write((char *)&t3, sizeof(Teacher));
	fs.write((char *)&t4, sizeof(Teacher));
	fs.flush();
	fs.close();

	fstream fs2("teacher", ios::binary | ios::in);
	if (!fs)
	{
		cout << "文件打开失败" << endl;
	}
	Teacher t;

	fs2.read((char *)&t, sizeof(Teacher));
	t.prinf();
	fs2.read((char *)&t, sizeof(Teacher));
	t.prinf();
	fs2.read((char *)&t, sizeof(Teacher));
	t.prinf();
	fs2.read((char *)&t, sizeof(Teacher));
	t.prinf();
	fs2.close();

	system("pause");
	return 0;
}

在这里插入图片描述


九、字符串流

  • 文件流以外存文件为对象输入输出。
  • 字符串流不是以外存文件为输出输入的对象,而是以内存中用户定义的字符数组(字符串)为输入输出的对象。即将数据输出到内存中的字符数组,或从字符数组(字符串)将数据读入 。
  • 字符流也称为内存流。
  • 用于从字符串读取数据
  • 功能
    1. 支持ofstream类的除open、close外的所有操作
    2. str函数可以返回当前已构造的字符串
  • 字符串流也有自己的缓冲区,开始时缓冲区为空。若向字符数组存入数据,随着向流插入数据,缓冲区数据不断增加,缓冲区满或遇到结束符,一起存入字符数组。若从字符数组中读数据,先将数据送到缓冲区,然后从缓冲区读入赋给变量。
  • 《C++》基础入门_16——输入输出流详讲_第12张图片

9.1 字符流类

  • istrstream
  • ostrstream
  • strstream
    和文件流类相同的基类,所以操作方式相似。
    向内存中的字符数组写数据就像向文件写数据。有3点不同:
    1. 输出时数据不是流向外存,而是流向内存的一个存储空间。
    2. 字符串流对象关联的不是文件,而是字符数组。因此不需要打开和关闭。
    3. 每个文件都有一个文件结束符,表示文件结束,而字符串流关联的数组无结束标志。用户需要自己指定结束的标志,在向数组写入全部数据后写上此结束字符。

9.2 建立输出字符流对象

ostrstream类提供的函数构造原型:
ostrstream :: ostrstream (char *buffer, int n,int mode=iso::out);

  1. buffer:指向字符数组首元素的首地址
  2. n: 指定的缓冲区大小。一般与字符数组大小相同
  3. 可选的参数,默认ios::out。

ostrstream strout (ch1,20);
建立输出字符串流对象strout,并与字符数组ch1关联,流缓冲区大小为20.

9.3 建立输入字符流对象

istrstream类提供的函数构造原型:
istrstream :: istrstream (char *buffer );
istrstream :: istrstream (char *buffer, int n);

  1. buffer:指向字符数组首元素的首地址
  2. n: 指定的缓冲区大小。一般与字符数组大小相同
  1. istrstream strin (ch1);
    建立输入字符串流对象strin,并与字符数组ch1关联,将ch1的全部数据作为流全部输入。
  2. istrstream strin (ch1,20);
    建立输入字符串流对象strin,并与字符数组ch1关联,将ch1的前20个字符作为流输入。

9.4 建立输入输出字符串流对象

strstream类提供的函数构造原型:
strstream :: strstream (char *buffer, int n,int mode);

  1. buffer:指向字符数组首元素的首地址
  2. n: 指定的缓冲区大小。一般与字符数组大小相同

strstream strio(ch ,sizeof(ch),ios::in|ios::out);
建立输入输出字符串流对象strio,并与字符数组ch关联,流缓冲区大小为字符数组ch的大小.

#include
#include
#include 
using namespace std;
struct Student {
	int sno;
	string name;
};
int main() {
	Student stu[3] = { 1001,"Tom",1002,"Rain",1003,"Sun" };
	char c[50];
	ostrstream strout(c, 30);
	for (int i = 0; i < 3; i++) {
		strout << stu[i].sno << " " << stu[i].name << endl;
	}
	strout << ends;
	cout << "array c:" << endl;
	cout << "array c:" << c << endl;
	return 0;
	/*
	array c:
	1001 Tom
	1002 Rain
	1003 Sun
*/
}

十、宽字符,宽字符串,宽流

  • 多字节字符(multibyte character):每个字符可以是一到多个字节不等,而某个字节序列的字符值由字符串或流(stream)所在的环境背景决定。
  • 使用C++标准库的iostream,可以方便地将控制台、文件、字符串以及其它可扩充的外部表示作为流来处理,但要处理中文,却会碰到很多问题。
  • 普通字符和字符串的缺陷: 一个汉字被拆成两个字符

    例:
    string s = “这是一个中文字符串”;
    s.size():返回18
    s.substr(3,2):得到的结果是“且”
    s.find(“且”):返回3

10.1 宽字符:wchar_t类型

  • 宽字符:对宽字符的支持其实是ANSI C标准的一部分,用以支持多字节表示一个字符。宽字符和Unicode并不完全等同,Unicode只是宽字符的一种编码方式。在ANSI中,一个字符(char)的长度为一个字节(Byte)。使用Unicode时,一个字符占据一个字.

  • C++在wchar.h头文件中定义了最基本的宽字符类型
    wchar_t :typedef unsigned short wchar_t;

    1. 一般占2个字节,可以直接存下一个汉字
    2. 宽字符的文字以“L”开头

    例: wchar_t c = L’人’;

10.2 宽字符串:wstring 类型

与string同源
1. typedef basic_string string;
2. typedef basic_string wstring;
>例如:
wstring s = L"这是一个中文字符串";
s.size():返回9

10.3 宽流:以宽字符为基本单位的流

  • wistream、wifstream、wistringstream、wostream、wofstream ,wostringstream、wios……
  • wcin、wcout、wcerr、wclog
  • 宽字符和宽字符串需要通过宽流输入输出
  • 宽流与普通流一一对应,彼此同源
    1. typedef basic_ifstream ifstream;
    2. typedef basic_ifstream wifstream;

10.4 为宽文件流配置编码方案

  • 文件以字节为单位,编码方案决定了宽字符和字节的对应关系

    例:L“ABCD”占4个字节,L“甲乙丙丁”占8个字节,这由编码方案体现

  • 配置方法:
    1. 用“代码页”编号构造locale对象
    2. 执行流的imbue成员函数

      示例
      locale loc(".936"); //创建本地化配置方案对象
      wcout.imbue(loc); //设置wcout对象的编码方案
      wcout << L"这是一个中文字符串" << endl; //输出字符串

10.5 locale

  • C/C++程序中,locale(即系统区域设置,即国家或地区设置)将决定程序所使用的当前语言编码、日期格式、数字格式及其它与区域有关的设置,locale设置的正确与否将影响到程序中字符串处理(wchar_t如何输出、strftime()的格式等)。因此,对于每一个程序,都应该慎重处理locale设置。

  • C locale和C++ locale是独立的。C locale用setlocale(LC_CTYPE, “”)初始化,
    C++ locale用std::locale::global(std::locale(“”))初始化。这样就可以根据当前运行环境正确设置locale。


	关于locale的详细讲解请点击:https://blog.csdn.net/haiross/article/details/45074355?utm_source=copy 

你可能感兴趣的:(C++,#,c++基础语法)