目录
从操作系统的角度来看,我们可以将每个输入输出设备都视作一个文件,程序的输入输出即可视为数据在文件—程序间的传输:
输入文件——>程序——>输出文件
对于C++,输入输出包括3方面:
1、标准I/O;(系统指定的标准设备如键盘、显示器)
2、文件I/O;(外存,如磁盘)
3、串I/O。(内存中指定空间,常用一个字符数组存储各类数据)
?
可以如下表示:
内存为字节流开辟内存缓冲区,用于存放数据。
反过来说,缓冲区中的数据即为流。
cout<<(cout流或标准输出流) 流路径===》
程序——>输出流——>输出缓冲区——>显示器
(保存于缓冲区时,当①缓冲区满②遇到endl,将数据送出)
(\n不会刷新缓冲区,但有时一些编译系统也不过多区分)
?
对于输入的数据,当按下回车键===》
键盘缓冲区——>输入缓冲区,并形成流。
·stdin(标准输入设备)为参数,使cin与设备关联。(cin流:标准输入流)
·istream(ostream也是)类中重载<<,对不同类型都要分别重载一次。
·cout<<"111"等价于cout.operator<<("111") ,调用的重载是(char *)型-----字符串111的值为其首字节的地址。
·cout将数据插入到cout流,函数返回流对象cout。
iostream头文件中定义了4种流对象:cin,cout,cerr,clog。
cerr是标准错误流,输出于标准错误设备(stderr)(区分于正常输出(stdout)),且cerr流中的信息只在显示器输出。它与clog的区别仅有,cerr不经过缓冲区存放、而是直接输出的。
cout.put('a'):
输出a;(专门输出单字符,参数为字符或ascii码)
连续调用:cout.put(65).put(66).put('\n');
基本等价于c语言中的putchar();
>>通常跳过空格和换行符等;
cin为非0值:输入流在正常状态,提取操作成功;(“文件结束符”:ctrl+Z或+D)
成员函数get:
一、cin.get();返回读入的字符(包括空白字符);
若遇到文件结束符,返回EOF(-1).
二、cin.get(ch);
读取失败返回0.
//前两种用法同C语言中的getchar
三、cin.get(字符数组,字符数n,终止符);
读取n-1个字符(!!!);失败返回0.
getline:
cin.getline(字符数组,字符数n,终止符);
?
(上面两个“字符数组”都可替换为字符指针;(存入其指向的数组))
(终止符由自己选定;)
(都读取n-1个字符,末尾加上'\0'。)
【对cin.getline和cin.get说明】:
①/cin.getline(arr,20),同样可读取空格,在读取完指定数目字符后或者遇到换行符时,停止读取。如例参数为20,则至多读取19个字符,余下空间存储自动添加在结尾的\0。
②/格式类似的,还有cin.get(arr,20),不同的是geline读取并丢弃换行符,而cin.get仅将其留在输入队列中。同样cin也会将回车键生成的换行符留下。一般后面再要输入时,得加一个无参数的cin.get(),读取下一个符号即处理留下的换行符。否则直接输入时会因为检测到换行符而认为已到行尾而不再读取。
?
eof:【cin.eof();】
若到达文件末尾(遇文件结束符)——>函数值非0。
peek:【cin.peek();】
观测当前指针所指字符。(之所以能观测下一个,是因为当读取完一个字符,指针已跳到下一个)
putback:【cin.putback(ch);】
前面用get/getline读取的某一字符ch返回到输入流并插入到当前指针位置。(往后读第一个便能读取)(例如,可用在一个字符数组c,终止后可以继续读取c)
ignore:【cin.ignore(n,终止符);】
括号内容含义:(跳过输入流中的n个字符,遇到终止符不再跳过)//也可不带参数或带一个。
默认:cin.ignore()==cin.ignore(1,EOF)。
(源程序文件.cpp,目标文件.obj,可执行文件.exe,数据文件date file.)
1、根据文件中数据组织形式,将文件分为两类:
ASCII文件/字符文件/文本文件:每个字节放一个ascii码
二进制文件/内部格式文件/字节文件:按在内存中的存储形式原样输出
?字符信息在内存中以ascii码存放,此时二种文件输出时,数据形式一样。
对于数字,则数据形式不同。(ascii为逐字,内部格式为数字值)
?· ascii文件,便于屏幕直接阅读,但存储时转换耗时多,占空间多。
2、文件流:以外存文件为I/O对象的数据流,每个文件流有一个内存缓冲区与之对应。
外存文件输入————>内存————>输出到外存文件
①文件流对象需要自己定义;(如定义输出文件流对象:ofstream outfile;)
②调用成员函数open:
outfile.open("f1.dat",ios::out);
//文件名可包括路径("c:\new\f1.dat"),后面是输入输出方式,默认是ios::out,可省写
?
?
//以上两步可合并:ofstream outfile("f1.dat",ios::out);——(调用了带参数的构造函数)
若打开失败,open返回0;对构造函数,失败时流对象值为0。
③成员函数close:
outfile.close();——解除该文件与文件流的关联。
④outfile<<a[i]....——向关联的磁盘文件输出数据。
exit(1);——应用程序终止并返回状态码1。
再次用不同方式打开一个文件前,先关闭。
/对于ascii文件,一字节放一字符,如:一篇英文文章的文本文件。操作就是正常文本读写。
/对二进制文件(内存数据的映像文件/字节文件),打开时要用ios::binary指定。可以作为既能输出又能输入的文件。↓↓↓
3、二进制文件操作
①成员函数write,read:
ofstream outfile("filename",ios::out|ios::binary);//ios::out可省略
outfile.write(p,50);
//将字符指针p指向的单元的开始的50个字节的内容,不加转换地写到与outfile关联的磁盘文件中
?
对于ifstream对象,读入50个字节存放在字符指针p所指空间内。
(上面括号内的形参(p处)是字符指针或者字符串的首地址,注意类型匹配!)
(abort();——>退出程序,同exit(1).)
两种结构体指针的write方法:
1、for循环
2、outfile.write((char*)&stru[0],sizeof(stru));
//输出数据间不必加空格(靠字节数来控制读入数据)
与位置标记(可以理解为,外存版的指针)有关的成员函数:
gcount()
tellg()/tellp()
seekg(位置)/seekp(位置)
也可用双参数(位移量,参照位置)
参照位置:
ios::beg(默认)
ios::cur
ios::end
字符串流不同于字符数组,可以按其他类型的数据形式读取数据。
向字符数组存入数据前,先将数据从二进制形式转换为ascii码放在缓冲区,后再发送。
从字符数组读取数据时,先将其中的ascii数据送到缓冲区后再发送,转换为二进制形式给程序中变量。
简而言之:
二进制——>输入给变量
ascii——>输出到屏幕
对于文件有文件结束符,对str,需自己指定一个特殊字符为结束标志。
①建立输出字符串流对象(并与字符数组关联)
ostrstream strout(arr,20); //20为缓冲区长度
?
?strout<<ends;? //用操作符ends向流插入一个'\0'。(通常作为字符串结束标志)
转换为ascii代码存入到字符数组。
②建立输入字符串流对象
istrstream strin(arr2,20); //若无20,则全部数据都作为流中内容
③输入输出对象:
strstream io(arr3,n,ios::in|ios::out);
输入字符串流和输出字符串流分别有流位置标记。
输出字符串流从数组首地址开始,会更新其中内容。
存取速度快但有生命周期,一般同main。