无论是标准流、串流还是文件流,流类始终遵循着相似的构造原则: 输出流与插入符配对, 输入流与提取符配对,插入即数据插入流类,提取即从流类提取数据到对象(如字符串等)
流类与流对象
I/O系统的任务就是在内存和外部设备间稳定可靠地传输数据和解释数据
头文件:iostream
iomanip:提供带参数操作算子
fstream:处理文件
标准流与流操作
标准流是C++预定义的对象,主要提供内存与外部设备进行数据交互的功能,包括数据提取、插入、解释及格式化处理等
提取流:>>
插入流:<<
流操作是流类的公有成员函数
cerr:连向显示器的标准错误输出流
clog:连向打印机的标准错误输出流
错误输出:报告程序中的错误信息,只显示,不保存
标准流连接的外部设备都是文本设备
标准流的主要工作是对内存中基本数据类型对象与文本之间进行翻译和传输
文本流:能够处理基本数据类型与文本之间I/O的流类
流提取运算符:>>,遇到文件结束符时返回0(false),否则返回对该对象的引用。
流提取将空白键、Tab、换行等特殊字符作为分隔符
istream流的函数:
int get();//提取字符作为返回值
istream& get(char&rch);//提取字符到rch,结束返回0.否则返回istream对象的引用
istream& get(char*pch, int nCount, char delim = '\n');//读取**nCount-1**个字符到pch中,遇到分隔符终止,在字符串后添加'\0'
istream& getline(char*pch, int nCount, char delim = '\n');//提取一行字符
istream& read(char* pch,int nCount);//非格式化读取pch地址,nCount提取字节数(结束符'\0'占用字节,读取字符串时,提取的字符比nCount少1,但是write函数能成功输出nCount个字符)
ostream流函数:
ostream& put(char ch)//无格式,插入一字节
ostream& write(const char*pch,int nCount)//无格式,插入一字节序列
//e.x.
ofstream outf;
double x = 0.618;
outf.write((char*)&x,8);//把8字节的数据写入输入流
流错误函数示例:
cin.clear()//清除状态字
格式控制
标志字:记录流的格式化状态,每一位用于记录一种格式
标志常量:每种格式对应的枚举常量
控制格式函数
flags([newFlag])//返回更新前标志字,参数更新标志字
setflags(newFlags,[oldFlags])//清除oldflags,设置newflags,返回更新前标志字
unsetf(flags)//清除
width()//设置宽度
fill()//设置填充字符
precision()//设置精度,即使有fixed,在科学计数法的情况下也会认定为有效位数而不会认定为小数位数
// |:同时设置多个标志字
//静态符号常量:防止标志字排斥
ios::basefield//value:dec|oct|hex,对浮点数无效
//补充:以下代码不会输出十六进制,因为没有清除原状态字
#include<iostream>
#include<fstream>
#include<iomanip>
using namespace std;
int main()
{
int x = 19;
cout.setf(ios::hex);
cout << x<<'\n';
}
ios::adjustfield//value:left|right|internal
ios::foatfield//value:scientific|fixed
格式控制符
控制符/控制算子:重载<<或>>的右操作数
iomanip中的控制符(部分)
resetiosflags(ios::lFlags)//清除标志位
setiosflags(ios:lFlags)//设置标志位
串流
串流操作
作用:istringstream获取多个串,并可被提取流提取多个串;ostringstream被插入多个串,利用其数据成员str()可被提取出串流,也可在初始化时指定被插入流的对象
头文件:sstream(C++)及strstream(C )
e.x.
//输入流的初始化及操作演示
string s1,s2;
istringstream input("a b c"[,n]); //n为open_mode,但实践表明似乎没用
input >> s1 >> s2;
cout << s1 << s2;
//输出ab
//输出流的无参数初始化及操作演示
double x = 3, y = 6;
ostringstream output;
output << x << ' ' << y << ' ' << x * y;//插入到数据成员str中
cout << output.str();
//输出3 6 18
//输出流的带参数初始化及操作演示
char buf[80];
ostrstream output(buf, sizeof(buf));
output << 5 << '*' << 6 <<'\0';//不要遗漏\0,不要超出数组限制,空格也能正常输出
cout << buf;
//输出5*6
文件处理
计算机用外存保存数据
保存在外存中的相关信息称为文件
C++把文件看成无结构的字节流
根据文件编码方式不同,分为文本文件与二进制文件
根据存取方式不同,分为顺序存取文件和二进制数据文件
头文件:ifstream\ofstream\fstream
打开和关闭文件
打开:
方式一:
流类 对象名
对象名.open(文件名,方式)
方式二:
流类 对象名(文件名,方式)
对象名:用户定义的流对象名
文件名:字符串类型,不在当前工作目录中需写出路径,指定路径注意分隔符用\
方式:文件打开方式
方式标识常量:
命名域:ios::
in//读方式打开
out//写
ate//at the end,文件指针指向末尾
app//append,将向文件输出的内容追加到文件末尾
binary//以二进制代码方式打开
e.x.
ifstream infile;
infile.open("data.dat",ios::in);
ofstream outfile("data.dat",ios::out);
关闭:
调用close()
关闭文件后,若流对象生存期没有结束,则流对象仍存在,还可以与其他文件连接
文本文件
使用文本文件流进行读/写操作。文本文件是顺序存取文件
文本文件用默认方式打开
描述一个对象的信息称为记录,文本文件没有记录逻辑结构。文本文件通常将记录放在一行(用换行符分隔的逻辑行中)
ifstream infile("1.txt", ios::out);
infile << "123445";//非法,标志字不能改变类型限制
//e.x.2
fstream infile("1.txt", ios::in);
infile << "123445";//不报错,但是写入无效
//e.x.3
ofstream infile("1.txt", ios::in);
infile << "123445";//不报错,但是写入无效
写模式应用示例:
#include<iostream>
#include<fstream> // 头文件!
using namespace std;
int main()
{
char filename[30], name[30];
int num, score;
ofstream outstuf; // 创建流对象
cout << "filename:\n";
cin >> filename;
outstuf.open(filename, ios::out); //写模式可改动文本文件内容,可创建一个名字为filename的文本文件,诞生在项目文件夹中
if (!outstuf)
{
cerr << "not open" << '\n';
abort();
}
outstuf << "students:\n";
cout << "input the name:\n";
while (cin >> name)
{
outstuf << name << ' ';
}
outstuf.close();//关闭文件
return 0;
}
读模式应用示例:
#include<iostream>
#include<string>
#include<sstream>
#include<strstream>
#include<fstream>
using namespace std;
int main()
{
char s[80],name[80];
ifstream instuf("you", ios::in);// 读方式打开
instuf.seekg(0, ios::beg);//seekg,即seek get,第一个参数为偏移量,第二个参数为起始位置(偏移前)
instuf.getline(s, 80);//提取一行
while (instuf >> name)//提取字符串
{
cout << name << ' ';
}
instuf.clear();//清除错误状态字
instuf.close();
return 0;
}
追加模式:app
二进制文件
二进制文件基本类型数据以二进制代码形式存放,二进制数据流不对写入或输出的数据进行类型转换
数据的解释由内存对象类型决定。
二进制文件的存储格式和内存格式一致,存储长度仅由数据类型决定。
二进制数据文件又称类型文件。由数据类型解释的一个单元称为文件的记录或元素
二进制文件的读/写完全由程序控制,无需经过格式化转换
文件打开方式:binary
读取数据:read
写入数据:write
文件打开后,系统自动生成两个隐含的流指针
//移动读指针
istream& seekg(long pos);//pos指针新位置(单位为字节)
istream& seekg(long off,ios::seek_dir dir);//off偏移量,dir参照位置
//enum seek_dir {beg = 0, cir = 1, end = 2};
//返回当前指向
long tellg();
input.seekg(0,ios::begin);
long pos = input.tellg();
写指针采用seekp\tellp.
二进制文件读写示例
#include<iostream>
#include<string>
#include<sstream>
#include<strstream>
#include<fstream>
using namespace std;
int main()
{
int i, j;
fstream f;
f.open("D:\\desktop\\data.dat", ios::out | ios::binary);
for (i = 1; i <= 10; ++i)
{
f.write((char*)&i, sizeof(int));
}//输入1 2 3 4 5 6 7 8 9 10到文件
f.close();
f.open("D:\\desktop\\data.dat", ios::in | ios::out | ios::binary);
f.seekg(0);
f.read((char*)&j, 1);
cout << j <<'\n';
f.seekg(0);
f.read((char*)&j, sizeof(1));
cout << j << '\n';
f.seekg(sizeof(int));
f.read((char*)&j, sizeof(int));
cout << j << '\n';
f.seekg(ios::end);
f.read((char*)&j, sizeof(1));
cout << j << '\n';
// output:
// 乱码
// 1
// 2
// 乱码
}
由于二进制不是用ASCII码解释,而是由字节序列去表示记录,所以ios::end不一定能表示最后一个完整记录的结束。所以完整读出数据的两种办法有:
1、用文件长度(记录个数)控制读写
2、在文件尾添加特殊标记