输入输出是指程序与外部设备交换信息
C++把输入输出看成是一个数据流
输入流:外围设备流向内存的数据
输出流:内存流向外围设备的数据
在C++中,输入输出不是语言所定义的部分,而是由标准库提供。
C++的输入输出分为:
基于控制台的I/O
基于文件的I/O
基于字符串的I/O
流其实是中间对象(可以调用函数,类类型 )
把键盘和屏幕连起来
C++程序不能直接与输入输出设备交换信息。输入输出是通过一个对象实现的。对象是输入输出设备在程序中的代理
每个I/O对象管理一个缓冲区,用于存储程序读写的数据
外围设备与对象批量交换数据
!这里插入图片描述](https://img-blog.csdnimg.cn/202105261929445.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzUxMjY1NTI4,size_16,color_FFFFFF,t_70)这里说的fstream 很明显第一个 f 表示 file ,文件。
所以 ifstream 表示写到文件里,(i表示in 写入)
ofstream 表示从文件中读出, (o表示out 读出)
因为都和文件相关,所以多了一个f
当用户在键盘上输入数据时,键盘输入的数据是存储在输入缓冲区中,在输入回车后,输入数据被移到输入缓冲区。当执行“>>”操作时,从输入缓冲区中取数据存入变量,如缓冲区中无数据,则等待从外围设备取数据放入缓冲区。
“<<”是将数据放入输出缓冲区。如有下列语句:
cout << “please enter the value:”;
系统将字符串常量存储在cout的缓冲区中
这里缓冲区满了就会输出。
程序正常结束。作为main函数返回工作的一部分,将真正输出缓冲区的内容,清空所有的输出缓冲区;
比如 " >>"从缓冲区中取出数据存入变量,如果缓冲区无数据则等待从外围设备取数据放入缓冲区。
“ << ”是 将数据放入输出缓冲区。
当缓冲区已满时,在写入下一个值之前,会刷新缓冲区;
用标准库的操纵符,如行结束符endl,显式地刷新缓冲区;///这就是为什么cout<
可将输出流与输入流关联起来。在这种情况下,在读输入流时,将刷新其关联的输出缓冲区。在标准库中,将cout和cin关联在一起,因此每个输入操作都将刷新cout关联的缓冲区。
*标准的输入输出流对象
cin是类istream的对象,它与标准输入设备(通常指键盘)连在一起。
cout是类ostream的对象,它与标准输出设备(通常指显示设备)连在一起。
cerr是类osteam的对象,它与标准错误输出设备连在一起。
clog是类ostream的对象,它与标准错误输出设备连在一起。
这里都是键盘和程序的关系
在输入输出的时候,不用指定类型(优于C语言的一点。)
格式这里指(间隔,输出几个数字,开头和结尾要不要加东西)
如果输出的指针变量是一个指向字符的指针时,C++并不输出该指针中保存的地址,而是输出该指针指向的字符串。
如果确实想输出这个指向字符的指针变量中保存的地址值,可以用强制类型转换,将它转换成void*类型。
#include
using namespace std;
int main()
{ char ptr = “abcdef”;
cout << "ptr指向的内容为: " << ptr << endl;
cout << “ptr中保存的地址为:” << (void)ptr
<< endl;
return 0;
}
cout的成员函数
put 将A显示,并且返回当前对象。
cout.put(‘A’).put(’\n’);
该语句在输出字符A后输出一个换行符。 (.)从左向右结合
例如: char buffer[] =“HAPPY BIRTHDAY”;
cout.write(buffer, 10 );
输出buffer的10个字节
流的成员函数 *** *** 与之相同作用的控制符
precision(n) setprecision(n) 设置精度为n位
width(n) setw(n) 设置字段宽度为n位
fill(c ) setfill(n ) 设置填充字符 c
C++提供了大量的用于执行格式化输入/输出的流操纵算子和成员函数。
功能:
整数流的基数:dec、oct、hex和setbase
设置浮点数精度: precision、setprecision
设置域宽: setw、wth
设置域填充字符: fill、setfill
输入流最常用的操作是流读取运算符。
流读取运算符通常会跳过输入流中的空格、tab键、换行符等空白字符。
当遇到输入流中的文件结束符时,流读取运算符返回0(false); 否则,流读取运算符返回对调用该运算符的对象的引用。
流读取运算符在读入EOF时返回0的特性使得它经常被用作为循环的判别条件,以避免选择特定的表示输入结束的值
EOF在各个系统中有不同的表示。在windows中是Ctrl+z
*** 代码示例***
#include
using namespace std;
int main()
{
int grade, highestGrade = -1;
cout << "Enter grade (enter end-of-file to end): ";
while (cin >> grade) {
if (grade > highestGrade) highestGrade = grade;
cout << "Enter grade (enter end-of-file to end): ";
}
cout << "\n\nHighest grade is: " << highestGrade << endl;
return 0;
}
最后输入ctrl + z 的时候程序停止
此时cin>>grade 整个式子变为0 (即False)
get函数用于读入字符或字符串
get函数有三种格式:
不带参数
带一个参数
带三个参数
while( (ch = cin.get( )) !=EOF ) cout<< ch;
将输入的字符回显在显示器上,直到输入EOF。
带一个字符类型的引用参数,它将输入流中的下一字符(包括空白字符)存储在参数中,它的返回 值是当前对象的引用。
例如,下面的循环语句将输入一个字符串,存入字符数组ch,直到输入回车。
cin.get(ch[0]);
for ( i = 0; ch[i] != ‘\n’; ++i) cin.get(ch[i+1]);
ch[i] = ‘\0’;
调用成员函数read可实现无格式输入。它有两个参数。第一个参数是一个指向字符的指针,第二个参数是一个整型值。这个函数把一定量的字节从输入缓冲区读入字符数组,不管这些字节包含的是什么内容。
例如: char buffer[80] ;
cin.read(buffer, 10 );
读入10个字节,放入buffer
如果还没有读到指定的字符数,遇到了EOF,则读操作结束。此时可以用成员函数gcount统计输入的字符个数
#include
using namespace std;
int main()
{
char buffer[80];
cout << “Enter a sentence:\n”;
cin.read(buffer, 20); //读键盘输入的数据 (放入缓冲区 )
cout << “\nThe sentence entered was:\n”;
cout.write(buffer, cin.gcount()); //从字符数组里写到屏幕上
cout << endl;
cout << “一共输入了” << cin.gcount() << “个字符\n”;
return 0;
}
输入输出流中的整型数默认为十进制表示。为了使流中的整型数不局限于十进制,可以插入hex操纵符将基数设为十六进制,插入oct操纵符将基数设为八进制,也可以插入dec操纵符将基数重新设为十进制
也可以通过流操纵符setbase来改变流的基数。该操纵符有一个整型参数,它的值可以是16,10或8,表示将整型数的基数设为十六进制,十进制或八进制
使用任何带参数的流操纵符,都必须包含头文件iomanip
流的基数值只有被显式更改时才会变化,否则一直沿用原有的基数。
#include
#include
using namespace std;
int main()
{
int n;
cout << "Enter a octal number: ";
cin >> oct >> n;
cout << “octal " << oct << n //octal 八进制
<< " in hexdecimal is:” << hex << n << ‘\n’; //转换位16进制
cout << “hexdecimal " << n
<< " in decimal is:” << dec << n << ‘\n’; //转换为十进制
cout << setbase(8) << “octal " << n
<< " in octal is:” << n << endl;
return 0;
}
格式化示例
#include
#include
using namespace std;
int main()
{
double x = 123.456789, y = 9876.54321;
for (int i = 9; i > 0; --i)
{
cout.precision(i); cout << x << '\t' << y << endl;
}
// 或 for (int i = 9; i > 0; --i)
// cout << setprecision(i) << x << '\t' << y << endl;
return 0;
}
设置域宽
设置域宽也可用于输入。当输入是字符串时,如果输入的字符个数大于设置的域宽时,C++只读入域宽指定的字符个数。如有定义
char a[9] , b[9] ;
执行语句
cin >> setw(5) >> a >> setw(5) >> b;
用户在键盘上的响应为
abcdefghijklm
则字符串a的值为“abcd”,字符串b的值为“efgh”。
tab键 就是缩进键,也可以重载
例如
ostream &操纵符名(ostream &os )
{
加入需要的操作
}
ostream & tab (ostream &os )
{return os<<‘\n’;}
#include
using namespace std;
ostream &tab(ostream &os) {return os << ‘\t’;}
int main()
{ int a=5,b=7;
cout << a << tab << b <
}
文件是驻留在外存储器上、具有标识名的一组信息集合,用来永久保存数据。
与文件相关的概念有:
数据项(字段)
记录
文件
数据库
如在一个图书管理系统中,有一个数据库。这个数据库由书目文件、读者文件及其它辅助文件组成。书目文件中保存的是图书馆中的所有书目信息,每本书的信息构成一条记录。每本书需要保存的信息有:书名、作者、出版年月、分类号、ISBN号、图书馆的馆藏号以及一些流通信息。其中书名是一个字段,作者也是一个字段。
C++语言把每一个文件都看成一个有序的字节流(把文件看成n个字节)
每一个文件以文件结束符(end-of-file marker)结束
当打开一个文件时,该文件就和某个流关联起来
与这些对象相关联的流提供程序与特定文件或设备之间的通信通道
定义一个流对象
打开文件:将流对象与文件关联起来
访问文件
关闭文件 :切断流对象与文件的关联
C++有三个文件流类型:(当作三个对象 的类)
ifstream:输入文件流
ofstream:输出文件流
fstream:输入输出文件流
如:ifstream infile;
用流对象的成员函数open打开文件
用流对象的构造函数打开文件
无论是成员函数open还是通过构造函数,都有两个参数:
打开的文件名
文件打开模式
如果文件打开失败,返回0
用成员函数close
对于输出文件,close会将缓冲区中的内容写入文件
main函数执行结束时,会关闭所有打开的文件
良好的程序设计习惯:文件访问结束时,关闭文件
例题
将数字1到10写入文件file,然后从file中读取这些数据,把它们显示在屏幕上。
首先用输出方式打开文件file。如文件file不存在,则自动创建一个,否则打开磁盘上的文件,并清空。用一个循环依次将1到10用流插入符插入文件,并关闭文件。然后,再用输入方式打开文件file,读出所有数据,并输出到屏幕上。
#include
#include
using namespace std;
int main()
{
int i = 0;
fstream fs; //1.定义一个流对象, fstream 可读可写
fs.open("test.txt"); //同时打开文件test //如果只想写文件 就 //fs.open("test.txt",ios::out)
if (!fs) { cerr << "create file error\n"; return 1; } //在没有打开时有提示
for (int i = 1; i <= 10; i++)
{
fs << i << ' ';//从左至右读 写入文件
}
fs.close(); //写好后关闭
fs.open("test.txt"); //再打开读数据
if (!fs) { cerr << "create file error\n"; return 1; } //在没有打开时有提示
while (fs >> i) cout << i << ' ';
fs.close();
return 0;
}
注意这里写 fstream 是不能直接打开一个不存在的文件,也不会创一个文件,所以需要自己在项目文件里添加一个test.txt 文件
虽然名字是test
但是在打开的时候,要加txt 的文件类型
要在屏幕上显示 ,需要cout
直接用fs 是做不到的
#include
#include
using namespace std;
int main()
{
ifstream fin("test.txt");
char s[80];
int i;
float x;
if (!fin) { cout << "cannot open input file\n"; return 1; }
fin >> i >> x >> s; cout << i << " " << x << s;
fin.close();
return 0;
}
#### 文件定位指针
文件定位指针:是一个long类型的数据 ,指出当前读写的位置
C++文件有两个定位指针:读指针和写指针
当文件以输入方式打开时,读指针指向文件中的第一个字节。
文件以输出方式打开时,写指针指向文件中的第一个字节。
当文件以添加方式打开时,写指针指向文件尾。
指定文件定位指针的值,从任意指定位置开始读写。
获取文件定位指针的当前位置 :成员函数tellg和tellp
设置文件定位指针的位置:成员函数seekg和seekp
***成员函数 seekg 和seekp
ios::beg(默认):相对于流的开头
ios::cur:相对于流当前位置
ios::end:相对于流结尾
```c++
#include
#include
using namespace std;
int main()
{
fstream in("file.txt");
int i;
if (!in) { cerr << "open file error\n"; return 1; }
in.seekp(10); //指针定位10个
in << 10; //输入20
in.seekg(0); //定位在文件头
while (in >> i) cout << i << ' ';
in.close();
return 0;
}
立即访问到文件甚至大型文件中指定的记录。
可以在不破坏其他数据的情况下把数据插入到随机访问文件中。
也能在不重写整个文件的情况下更新和删除以前存储的数据。
```c++
#include
#include
using namespace std;
int main()
{
ofstream out("file.txt"); //定义输出流,并与文件file关联
ifstream in; //定义一个输入流对象
fstream io;
int i;
//将1~10写到输出流对象
if (!out) { cerr << "create file error\n"; return 1; }
for (i = 1; i <= 10; ++i) out.write(reinterpret_cast (&i), sizeof(int));
out.close();
}
二进制文本
内容是 人不认识的字符
如果是文本文件就是12345678910