C++——流类库和输入/输出
前言
数据是怎么写道磁盘的?
代码里面我们一个读写调用似乎就能将数据从磁盘读写。仿佛代码是直接和磁盘打交道。以我们最常见的笔记本、或台式机的磁盘SATA盘为例,其受南桥上ATA控制器支配,这里面传输的ATA指令。至少我们代码里面是没有处理这部分的,所以我们代码直接操控磁盘说不通。现实情况是,C++通过IO流库和磁盘打交道。
IO流库
C++语言中并没有输入/输出语句,而是在标准库里包含了一个I/O流类库,它与标准模板库同为C++标准库中最重要的组成部分。数据从一个对象到另一个对象的传送被抽象为“流”。数据的输入/输出就是通过输入/输出流来实现的。 流是一种抽象的概念,负责在数据的产生者和数据的使用者之间建立联系,并管理数据的流动。
流类体系
整个流类体系是一个派生类体系。按ANSI C++标准,类ios是抽象类,它的析构函数是虚函数,它的构造函数为保护的,作为所有基本流类的基类。
ios提供了对流进行格式化输入输出和错误处理的成员函数。所有派生都是公有派生。
istream类提供完成提取(输入)操作的成员函数
ostream类提供完成插入(输出)操作的成员函数。
iostream类是前两者的组合。
streambuf是一个独立的类,只是ios有一个保护访问限制的指针指向它。streambuf的作用是管理一个流的缓冲区。
在流类库中,最重要的两部分功能为:
①标准输入/输出(standard input/output)
②文件处理
在C++的流类库中定义了四个全局流对象,可以完成人机交互的功能(要使用这四个功能,必须包含<iostream.h>文件。):
①cin 标准输入流对象,键盘为其对应的标准设备。带缓冲区
②cout 标准输出流对象,显示器为标准设备。带缓冲区,一旦错误发生立即显示。
③cerr 标准错误输出流,输出设备是显示器。非缓冲区
④clog 标准错误输出流,输出设备是显示器。带缓冲区
输入输出格式控制
C++在类ios中提供格式化输入输出。这些格式是对所有文本方式的输入输出流均适用。格式控制符定义为公有的无名的枚举类型:
1 enum{ skipws=0x0001, //跳过输入中的空白字符 2 left=0x0002, //输出左对齐 3 right=0x0004, //输出右对齐 4 internal=0x0008, //在输出符号或数制字符后填充 5 dec=0x0010, //在输入输出时将数据按十进制处理 6 oct=0x0020, //在输入输出时将数据按八进制处理 7 hex=0x0040, //在输入输出时将数据按十六进制处理 8 showbase=0x0080, //在输出时带有表示数制基的字符 9 showpoint=0x0100, //输出浮点数时,必定带小数点 10 uppercase=0x0200, //输出十六进制,用大写 11 showpos=0x0400, //输出正数时,加”+”号 12 scientific=0x0800, //科学数方式输出浮点数 13 fixed=0x1000, //定点数方式输出实数 14 unitbuf=0x2000, //插入后,立即刷新流 15 stdio=0x4000} //插入后,立即刷新stdout和stderr 16 17
View Code
1 #include<iostream> 2 using namespace std; 3 4 void main() 5 { 6 for (int i=1; i <=10; ++i) 7 { 8 for (int j = 1; j <= 10; ++j) 9 { 10 cout.width(5); 11 cout.flags(ios::left); 12 cout << i * j; 13 } 14 cout << endl; 15 } 16 }
View Code
该枚举量说明中每一个枚举量实际对应两字节数据(16位)中的一个位,所以可以同时采用几个格式控制,只要把对应位置1即可,这样既方便又节约内存。取多种控制时,用或“|”运算符来合成,合成为一个长整型数,在ios中为:
1 protected: 2 long x_flags;
View Code
类ios中还设置了三个输入输出流格式控制标志:
1 protected: 2 int x_precision; //标志浮点数精度,缺省为6位 3 int x_width; //输出域宽,缺省域宽为0, 4 //重设域宽只对其后第一输出项有效,如域宽不足,则不受限制 5 char x_fill; //标志域宽有富余时填入的字符
View Code
流操作子(setiosflags stream manipulator)
可代替流格式控制成员函数,但绝大多数流操作子VC++不支持
#include<iostream> using namespace std;void main() {int a = 12345678;cout << hex << a << endl; }
View Code
文件的输入输出
这里的文件指的是磁盘文件。C++根据文件(file)内容的数据格式,可分为两类:二进制文件和文本文件。文本文件由字符序列组成,也称ASCII码文件,在文本文件中存取的最小信息单位为字符(character),而二进制文件中存取的最小信息单位为字节(Byte)。
文件的使用步骤
①声明一个文件流对象,这又被称为内部文件:
ifstream ifile;//只输入用
ofstream ofile;//只输出用
fstream iofile;//既输入又输出用
②使用文件流对象的成员函数打开一个磁盘文件。这样在文件流对象和磁盘文件名之间建立联系。文件流中说明了三个打开文件的成员函数。
void ifstream::open(const char*,int =ios::in,int=filebuf::openprot); void ofstream::open(const char *,int=ios::out,int=filebuf::opernprot); void fstream::open(const char*,int,int=filebuf::openprot);
View Code
第一个参数为要打开的磁盘文件名。
第二个参数为打开方式,有输入(in),输出(out)等,打开方式在ios基类中定义为枚举类型。
文件打开方式是在ios类中定义的,公有枚举成员:
enum open_mode{ in=0x01, //打开文件用于输入操作(从文件读取),文件指针在文件头out=0x02, /*打开文件用于写入文件。如文件不存在,则建立,但指定目录必须存在,否则建立文件失败。如文件存在,未同时设app,ate,in则文件清空*/ ate=0x04,//打开文件用于输入/输出,文件指针在文件尾,但新数据可写到任何位置 app=0x08, //打开文件用于输出,但从尾部添加,新数据只能添加在尾部trunce=0x10, //打开文件,并清空它,以建立新文件nocreate=0x20, //如文件存在则打开,不存在并不创建新文件noreplace=0x40,//如文件不存在则创建,如文件存在则只能设为ate及app方式binary=0x80 //以二进制方式打开文件 };
View Code
第三个参数为指定打开文件的保护方式,一般取缺省。
三个文件流类都重载了一个带缺省参数的构造函数,功能与open函数一样:
ifstream::ifstream(const char*,int=ios::in,int=filebuf::openprot); ofstream::ofstream(const char*,int=ios::out,int=filebuf::openprot); fstream::fstream(const char*,int,int=filebuf::operprot);
View Code
所以1,2两步可合成:
fstream iofile(“myfile.txt”,ios::in|ios::out);
View Code
打开文件也应该判断是否成功,若成功,文件流对象值为非零值,不成功为0(NULL),文件流对象值物理上就是指它的地址。
因此打开一个文件完整的程序为:
fstream iofile(”myfile.txt”,ios::in|ios::out); if(!iofile){//失败退回操作系统cout<<”不能打开文件:”<<”myfile,txt”<<endl;exit(1); }
View Code
③使用提取(>>)和插入(<<)运算符对文件进行读写操作,或使用成员函数进行读写
④关闭文件。三个文件流类各有一个关闭文件的成员函数
void ifstream::close(); void ofstream::close(); void fstream::close();
View Code
使用很方便,如:iofile.close();
关闭文件时,系统把该文件相关联的文件缓冲区中的数据写到文件中,保证文件的完整,收回与该文件相关的内存空间,可供再分配,把磁盘文件名与文件流对象之间的关联断开,可防止误操作修改了磁盘文件。如又要对文件操作必须重新打开。关闭文件并没有取消文件流对象,该文件流对象又可与其他磁盘文件建立联系。文件流对象在程序结束时,或它的生命期结束时,由析构函数撤消。它同时释放内部分配的预留缓冲区。
代码演示
#include<iostream> #include<fstream> using namespace std; int main() {int ar[] = {1,2,3,4,5,6,7,8,9};//1 ofstream ofile;//2ofile.open("test.txt",ios::out);if (!ofile){cerr << "Open File Fail!" << endl;exit(1);}//3for (int i = 0; i < sizeof(ar) / sizeof(int);++i){//cout<<ar[i]<<" ";ofile << ar[i] << " ";}ofile.close();return 0; }
View Code
#include<iostream> #include<fstream> using namespace std; int main() {int ar[] = {1,2,3,4,5,6,7,8,9};ofstream ofile("test.txt", ios::out);if (!ofile){cerr << "Open File Fail!" << endl;exit(1);}//3for (int i = 0; i < sizeof(ar) / sizeof(int);++i){//cout<<ar[i]<<" ";ofile << ar[i] << " ";}ofile.close();return 0; }
View Code
再见文件内容读入到数组
#include<iostream> #include<fstream> using namespace std; int main() {int ar[9];ifstream ifile("test.txt", ios::out);if (!ifile){cerr << "Open File Fail!" << endl;exit(1);}//3for (int i = 0; i < sizeof(ar) / sizeof(int);++i){//cout<<ar[i]<<" ";ifile >> ar[i];}ifile.close();return 0; }
View Code
二进制文件读写
C++提供了对二进制文件进行读取的成员函数:
istream&istream::read(char *,int); //从二进制流提取 istream&istream::read(unsigned char*,int); istream&istream::read(signed char *,int);
View Code
第一个参数指定存放有效输入的变量地址
第二个参数指定提取的字节数
C++提供了对二进制文件进行写入的成员函数:
ostream&ostream::write(const char *,int); ostream&ostream::write(const unsigned char *,int); ostream&ostream::write(const signed char *,int);
View Code
第一个参数指定输出对象的内存地址
第二个参数指定插入的字节数
之前用循环每次像数组读取一个字符,速度很慢。可以采用二进制读取,在读取二进制文件之前需要构造二进制文件。
1 #include<iostream> 2 #include<fstream> 3 using namespace std; 4 int main() 5 { 6 int ar[] = { 1,2,3,4,5,6,7,8,9 }; 7 int br[9]; 8 ofstream ofile("test.txt", ios::out|ios::binary); 9 if (!ofile) 10 { 11 cerr << "Open File Fail!" << endl; 12 exit(1); 13 } 14 ofile.write((char*)ar,sizeof(ar)); 15 ofile.close(); 16 ifstream ifile("test.txt", ios::in | ios::binary); 17 if (!ifile) 18 { 19 cerr << "Open File Fail!" << endl; 20 exit(1); 21 } 22 ifile.read((char*)br, sizeof(br)); 23 return 0; 24 }
View Code
读函数并不能知道文件是否结束,可用状态函数int ios::eof()来判断文件是否结束。必须指出系统是根据当前操作的实际情况设置状态位,如需根据状态位来判断下一步的操作,必须在一次操作后立即去调取状态位,以判断本次操作是否有效。
使用二进制文件,可以控制字节长度,读写数据时不会出现二义性,可靠性高。同时不知格式是无法读取的,保密性好。
文件结束后,系统不会再读,但程序不会自动停下来,所以要判断文件中是否已没有数据。
如写完数据后没有关闭文件,直接开始读,则必须把文件定位指针移到文件头。
如关闭文件后重新打开,文件定位指针就在文件头。
文件随机访问
C++把每一个文件都看成一个有序的字节流,每一个文件或者以文件结束符(end of file marker)结束,或者在特定的字节号处结束。
当打开一个文件时,该文件就和某个流关联起来了。对文件进行读写实际上受到一个文件定位指针(file position pointer)的控制。
输入流的指针也称为读指针,每一次提取操作将从读指针当前所指位置开始,每次提取操作自动将读指针向文件尾移动。
输出流指针也称写指针,每一次插入操作将从写指针当前位置开始,每次插入操作自动将写指针向文件尾移动。
在C++中可以由程序移动文件指针,从而实现文件的随机访问,即可读写流中任意一段内容。一般文本文件很难准确定位,所以随机访问多用于二进制文件。
在ios类中说明了一个公有枚举类型:
enum seek_dir{beg=0, //文件开头cur=1, //文件指针的当前位置end=2 //文件结尾 };
View Code
istream类中提供了如下三个成员函数:
istream&istream::seekg(streampos); //指针直接定位 istream&istream::seekg(streamoff, ios::seek_dir); //指针相对定位 long istream::tellg(); //返回当前指针位置
View Code
流的指针位置类型streampos和流的指针偏移类型streamoff定义为长整型,也就是可访问文件的最大长度为4G
datafile.seekg(-20L,ios::cur);表示将文件定位指针从当前位置向文件头部方向移20个字节。 datafile.seekg(20L,ios::beg);表示将文件定位指针从文件头向文件尾方向移20个字节。 datafile.seekg(-20L,ios::end);表示将文件定位指针从文件尾向文件头方向移20个字节。 tellg()和seekg()往往配合使用。指针不可以移到文件头之前或文件尾之后。
View Code
ostream类也提供了三个成员函数管理文件定位指针,它们是:
ostream&ostream::seekp(streampos); ostream&ostream::seekp(streamoff,ios::seek_dir); long ostream::tellp();
View Code
为了便于记忆,函数名中g是get的缩写,而p是put的缩写。
借助二进制读写优化文件读取,代码演示
#include<iostream> #include<fstream> using namespace std; int main() {int ar[] = {12,23,34,45,56,67,78,89,90,100};ofstream ofile("test.txt", ios::out|ios::binary);if (!ofile){cerr << "Open File Fail!" << endl;exit(1);}ofile.write((char*)ar, sizeof(ar));ofile.close();ifstream ifile;ifile.open("test.txt", ios::in | ios::binary);if (!ifile){cerr << "Open File Fail!" << endl;exit(1);}int pos;int value;while (1){cout << "请输入位置:>" << endl;cin >> pos;ifile.seekg((long)(pos * sizeof(int)), ios::beg);ifile.read((char*)&value, sizeof(int));cout << "value = " << value << endl;}ifile.close();return 0; }
View Code
文件与对象
在面向对象的程序设计中,信息总是放在对象的数据成员里。这些信息最终应该保存到文件中。当程序开始运行时,就要根据打开的文件重新创建对象。在运行过程中,放在对象的数据成员里的信息得到利用和修改。运行结束时必须把这些信息重新保存到文件中,然后关闭文件。
磁盘文件打开时建立的内部文件流是在运行时动态分配的资源。在面向对象的C++程序设计中,文件应该在构造函数中打开,并创建对象;而在析构函数中保存和关闭文件,并撤销对象。这样,与动态安排的其他资源一样,当撤销对象时,能自动释放资源。特别在程序发生异常时,C++系统有异常处理机制,该机制要求动态分配的资源是在类对象中,这样C++保证退出异常点时资源得到完整的释放。
对文件而言,释放资源同时包括将对象中的信息再次存入磁盘文件。在程序运行过程中,应该将信息适时保存到相应的磁盘文件中,以免数据意外丢失。
代码演示
1 #include<iostream> 2 #include<fstream> 3 using namespace std; 4 5 class Complex; 6 ostream& operator<<(ostream &out, const Complex &c); 7 class Complex 8 { 9 friend ostream& operator<<(ostream &out, const Complex &c); 10 public: 11 Complex() :m_real(0), m_img(0) 12 { 13 ifstream ifile; 14 ifile.open("data.dat",ios::in); 15 if (!ifile) 16 { 17 cerr << "Open File Fail" << endl; 18 exit(1); 19 } 20 ifile >> m_real >> m_img; 21 ifile.close(); 22 } 23 Complex(int real, int imag) 24 { 25 m_real = real; 26 m_img = imag; 27 } 28 ~Complex() 29 { 30 ofstream ofile; 31 ofile.open("data.dat", ios::in); 32 if (!ofile) 33 { 34 cerr << "Open File Fail" << endl; 35 exit(1); 36 } 37 ofile << m_real <<" "<< m_img; 38 ofile.close(); 39 } 40 void SetComplex(int real, int imag) 41 { 42 m_real = real; 43 m_img = imag; 44 } 45 private: 46 int m_real; 47 int m_img; 48 }; 49 50 ostream& operator<<(ostream &out, const Complex &c) 51 { 52 out << "(" << c.m_real << "," << c.m_img << ")" << endl; 53 return out; 54 } 55 56 int main() 57 { 58 Complex c; 59 cout << c << endl; 60 c.SetComplex(10, 60); 61 cout << c << endl; 62 return 0; 63 }
View Code
转载于:https://www.cnblogs.com/kelamoyujuzhen/p/9558350.html
C++——流类库和输入/输出相关推荐
- 实验8 群体类、流类库与输入/输出(4学时)
一. 实验目的 了解链表类的定义与实现,学习其使用方法: 了解栈类的定义与实现,学习其使用方法: 了解队列类的定义与实现,学习其使用方法: 了解C++标准模板库STL的使用方法. 熟悉流类库中常用的类 ...
- 第15章-输入/输出 --- 理解Java的IO流
(一)理解Java的IO流 JAVA的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出(键盘.文件.网络连接等)抽象表述为"流"( ...
- 习题八 I/O流类库
一.填空题 (1)在C++的输入输出系统中,最核心的对象是 流 .执行输入和输出操作的类体系叫做 流类 . (2)当实际进I/O操作时, ...
- Java的输入/输出
在Java中,有输入和输出,也就是IO,然后给大家介绍一下: IO(输入/输出)是比较抽象的,看不到明显的运行效果,但输入和输出是所有程序都必需的部分.使用输入机制,允许程序读取外部(包括来自磁盘.光 ...
- 输入/输出(全称:Input Output)
IO(输入/输出)是比较抽象的,看不到明显的运行效果,但输入和输出是所有程序都必需的部分. 使用输入机制,允许程序读取外部数据(包括来自磁盘.光盘等存储设备的数据.来自网络的数据). 用户输入数据:使 ...
- c++中的IO流(流的概念和流类库的结构,标准的输入输出流)
流的概念和流类库的结构 程序的输入指的是从输入文件将数据传送给程序,程序的输出指的是从程序将数据传送给输出文件 c++输入输出包含以下三个方面的内容 对系统指定的标准设备的输入输出.即从键盘输入数据, ...
- c++I/O流的概念和流类库的结构
I/O流的概念和流类库的结构 程序的输入 程序的输出 C++输入输出包含以下三个方面的内容 C++的I/O对C的发展--类型安全和可扩展性 与iostream类库有关的头文件 在iostream头文件 ...
- 实验 7:流类库与输入输出
一.实验目的 理解流的概念 熟悉流类库中常用的类及成员函数用法 熟悉 I/O 格式控制方法,掌握常用格式控制 了解文件 I/O,掌握文件 I/O 基本用法 二.实验准备 结合第 11 章教材.课件,复 ...
- 常用的I/O流类库操纵符
当使用cin,cout进行数据的输入和输出时,无论处理的是什么类型的数据,都能够自动按照正确的默认格式处理.但是这还不够. C++I/O流类库提供了一些操纵符,可以直接嵌入到输入输出语句中来实现I/O ...
最新文章
- java 获取utc,如何在Java 8中获取UTC + 0日期?
- BZOJ 2037 Sue的小球
- 7.2.2 - 并发多线程 开启进程的两种方式
- 自己实现多线程的socket,socketserver源码剖析
- Linux系统磁状态检测,检测Linux硬件状态
- mysql数据库备份到oss_备份MySQL数据库并上传到阿里云OSS存储
- 用计算机探索规律反思,用计算器探索规律教学反思
- 百度地图隐藏LOGO显示
- freecplus框架简介
- Redis学习笔记三:Redis的数据类型
- pytroch model??(查看官方模型写法)
- java 对文件名非法字符处理
- Symantec Endpoint Protection(SEP) 离线病毒库下载与升级
- 中华英才网竞品分析报告2016
- python turtle后退_Turbot与python教程-实现后退
- PowerPoint超链接字体颜色修改、怎么去掉超链接下划线
- php发送邮件二种方法 php使用smtp发送邮件
- 程序员的职业病,一定要注重身体健康才是最重要的
- html项目的致谢词,论文致谢词(精选10篇)
- 计算机网络中常见的各层协议