目录

  • 简介
  • ios类库
  • streambuf类库
  • 标准I/O流——iostream
  • 预定义流对象
  • cin
  • cout
  • 标准输出流
  • put()
  • write()
  • 标准输入流
  • get()
  • getline()
  • read()
  • ignore()
  • gcount()
  • peek()
  • 文件流
  • 文件流对象的创建
  • 文件打开和关闭
  • 文本文件的读写
  • 二进制文件的读写
  • 文件随机读写
  • 字符串流


简介

I/O流类库是C++标准库的重要组成部分,它主要包括ios类库和streambuf类库。其中,ios类库提供流的高级I/O操作,streambuf类库主要负责缓冲区的处理。

ios类库

iostream不能用printf吗 iostream有没有printf_ios

抽象基类ios被istream、ostream类继承,其中istream类是输入流类,ostream类是输出流类,它们定义了输入流和输出流的基本特性。

  1. ifstream类:文件输入流类,支持文件的读操作。
  2. ofstream类:文件输出流类,支持文件的写操作。
  3. istringstream类:字符串输入流类,支持字符串的输入操作。
  4. ostringstream类:字符串输出流类,支持字符串的输出操作。
  5. iostream类
  1. fstream类:文件输入/输出流类,支持文件的读写操作。
  2. stringstream类:字符串输入/输出流类,支持字符串的输入和输出操作。

streambuf类库

iostream不能用printf吗 iostream有没有printf_文件流_02

streambuf类是一个抽象类,提供了缓冲区操作接口,如设置缓冲区、从缓冲区提取字节、向缓冲区插入字节等。
streambuf类派生了3个类,分别是stdiobuf类、filebuf类、stringstreambuf类。其中,stdiobuf类用于标准I/O缓冲区管理,filebuf类用于文件缓冲区管理,stringstreambuf类用于内存缓冲区管理。

标准I/O流——iostream

标准输入流和标准输出流的一系列操作方法都是由istream和ostream两个类提供的,这两个类继承自抽象基类ios,它们预定义了标准输入流对象和标准输出流对象,并且提供了多种输入/输出方法。

预定义流对象

C++提供了四个预定义流对象,包括cin、cout、cerr和clog。

预定义流对象

说明

类型

cin

处理标准输入(键盘输入),有缓冲

istream

cout

处理标准输出(屏幕输出),有缓冲

ostream

cerr

处理标准错误信息,无缓冲

ostream

clog

处理标准错误信息,有缓冲

ostream

cin

cin与运算符“>>”结合使用,用于读入用户输入,以空白(包括空格、Enter、Tab)为分隔符。

cout

cout与运算符“<<”结合使用,用于向控制台输出信息。在用cout输出变量值时,“<<”运算符会根据变量的数据类型自动匹配并正确输出。

  • 指定输出数字格式

通过C++标准库提供的标志位和操作符控制格式,这些操作符位于iomanip头文件。

#include <iostream>
#include <iomanip>
using namespace std;
int a = 10;
cout << "输出十进制" << a << endl; //10
cout << "输出八进制" << oct << a << endl; //12
cout << "输出十六进制" << hex << a << endl;//a
  • 指定数据精度

使用setprecision()函数可以设置浮点类型输出所需精度数据。

#include <iostream>
#include <iomanip>
double pi = 3.141592653589;
cout << setprecision(5) << pi << endl; //3.1416
  • 指定域宽、对齐方式、填充方式的数据

C++提供了setw()函数用于指定域宽,setiosflags()函数用于设置对齐方式,setfill()函数用于设置填充方式。

#include <iostream>
#include <iomanip>
double pi = 3.141592653589;
cout << setprecision(5) <<setfill('*')<<setw(10)<<setiosflags(ios::left)<< pi << endl;//3.1416****

标准输出流

ostream类除了预定义流对象cout,还提供了成员函数用于输出数据,比较常用的两个成员函数为put()函数和write()函数。

put()

put()函数用于输出单个字符,函数返回值为ostream类对象引用,所以可以连续调用。

cout.put('a').put('\n').put('d');
write()

write()函数用于输出一个字符串,第一个参数str表示字符串;第二个参数count表示输出的字符个数,其同样可以连续调用。

cout.write("hello",5).write(",world",6);//hello,world
//不满5个会用空格填满

标准输入流

istream类预定义了输入流对象cin,并且重载了“>>”运算符,输入流对象与“>>”运算符结合使用,可以输入各种类型的数据。此外,istream类还提供了成员函数用于输入数据,如get()函数、getline()函数、read()函数等

get()

istream类重载了多个get()函数。常用的重载形式有以下三种。

int get(); //是从输入流读取一个字符,返回该字符的ASCII码值
istream& get(char &ch);//从输入流读取一个字符存储到字符ch中
istream& get(char *dst,streamsize count,char delimiter);//delimiter默认'\0',表示结束符,count表示读取字符串长度
char ch;
cout << "请输入一个字符串:"<< endl;
cout << "第一种形式:" << cin.get() << endl;
cin.get(ch);
cout << "第二种形式:" <<ch << endl;
char dst[10];
cin.get(dst, 10,' ');
cout << "第三种形式:" <<dst << endl;

iostream不能用printf吗 iostream有没有printf_iostream不能用printf吗_03

getline()

getline()函数用于从输入流中读取字符,直到读取到指定长度的字符或遇到终止字符时结束读取。

istream& getline(char *dst,streamsize count);//读取指定大小字符,无结束符。
istream& getline(char *dst,streamsize count,char delimiter);
cin.getline(ch, 10); //实际读取9个字符
cout << "第一种形式:" << ch << endl;
cin.getline(ch1,10,'a'); //遇到字符'a'就结束读取
cout << "第二种形式:" <<ch1 << endl;
read()

read()函数用于从输入流中读取指定字符个数的字符串,read()函数在读取数据时,对读取到的字节序列不作任何处理。read()函数不会识别换行符、空格等特殊字符,遇到换行符’\n’也不会结束读取。

istream& read(char *dst,streamsize count);
char ch[10];
cout << "请输入一个字符串:"<< endl;
cin.read(ch, 10);
cout <<"输出:"<< ch << endl;

iostream不能用printf吗 iostream有没有printf_ios_04

ignore()

ignore()函数的作用是跳过输入流中的n个字符,参数delimeter表示结束符,在跳跃过程中,如果遇到结束符就结束跳跃。ignore()函数不识别换行符、空格、制表符等特殊字符。

istream& ignore(streamsize count,char delimiter);
char ch[10];
cout << "请输入一个字符串:"<< endl;
cin.ignore(1);
cin.getline(ch, 10);
cout <<"输出:"<< ch << endl;

iostream不能用printf吗 iostream有没有printf_ci_05

gcount()

gcount()函数的作用是计算上一次读取到的字符个数。

streamsize gcount() const;
char ch[10];
cout << "请输入一个字符串:"<< endl;
cin.ignore(1);
cin.getline(ch, 10);
cout <<"输出:"<< ch << endl;
cout <<"上次读取长度:"<< cin.gcount();

iostream不能用printf吗 iostream有没有printf_ci_06

peek()

peek()函数的作用是检测输入流中待读取的字符,返回检测字符的ASCII码值。peek()函数只是检测待读取的字符,但并不会真正读取它。

int peek();
char s;
cout << "请输入一个字符串:"<< endl;
s = cin.peek();
cout << "待检测字符:" << s << endl;
cin.get(s);
cout << s;

iostream不能用printf吗 iostream有没有printf_文件流_07

文件流

文件流是以磁盘中的文件作为输入、输出对象的数据流。输出文件流将数据从内存输出到文件中,这个过程通常称为写文件;输入文件流将数据从磁盘中的文件读入内存,这个过程通常称为读文件。

文件流对象的创建

文件流不像标准I/O流预定义了输入流对象和输出流对象,使用文件流时,需要创建文件流对象。
C++提供了三个类支持文件流的输入、输出,这三个类都包含在fstream头文件中。

  • ifstream:输入文件流类,用于实现文件的输入。
  • ofstream:输出文件流类,用于实现文件的输出。
  • fstream:输入/输出文件流类,可同时实现文件的输入和输出。
  1. 无参构造

ifstream类、ofstream类和fstream类都提供了默认无参构造函数,可以创建不带参数的文件流对象。

#include <fstream>
ifstream ifs; //文件输入流对象
ofstream ofs;//文件输出流对象
fstream fs;//文件输入、输出流对象
  1. 有参构造

在创建文件流对象时可以指定文件名和文件打开模式。

ifstream ifs("filename",ios::in);//打开模式默认是ios::in
ofstream ofs("filename", ios::out);//打开模式默认是ios::out
fstream fs("filename", ios::in|ios::out);//打开模式默认是ios::in|ios::out

文件打开和关闭

文件最基本的操作就是打开和关闭,在对文件进行读写之前,需要先打开文件;读写结束之后,要及时关闭文件。

  • 文件打开
  1. 方式一:有参构造

在创建文件流对象时传入文件名和文件打开模式即可打开文件。

  1. 方式二:open()

ifstream类、ostream类和fstream类都提供了成员函数open()用于打开文件,如果打开文件失败,文件流对象会变为0。

void open(const char* filename,int mode);

参数mode选项如下图:

iostream不能用printf吗 iostream有没有printf_iostream不能用printf吗_08


//文件打开失败

  • 文件关闭

ifstream类、ostream类和fstream类都提供了成员函数close()用于关闭文件。

fstream fs("xxx.txt", ios::in);
if (!fs) {
	cout << "文件打开失败" << endl;
}
fs.close();

文本文件的读写

  1. 利用<<、>>

使用提取运算符“>>”和插入运算符“<<”。

fstream fs("xxx.txt", ios::out);
if (!fs) {
	cout << "文件打开失败" << endl;
	exit(0);
}
char c[40];
cout << "输入写入文件的数据:";
cin >> c;
fs << c;
fs.close();
fs.open("xxx.txt", ios::in);
char d[40];
fs >> d;
cout << endl<< "文件读取成功,内容:" << d << endl;
fs.close();

iostream不能用printf吗 iostream有没有printf_ci_09

备注:文件打开后记得要关闭,不然再次打开就会有bug。

  1. 调用文件流类的成员函数读写文件

文件流类继承了istream类和ostream类的成员函数get()、getline()和put(),通过调用这些成员函数,文件流对象也可以完成文件的读写。

除此还有几个实用函数。

文件流成员函数

说明

bool eof() const

检测文件是否到达末尾,是返回true

bool bad() const

检测文件在读写过程中是否出错

bool good() const

检测文件在读写过程中是否正常

bool fail() const

也用于检测在读写过程中是否出错,比bad()函数的检错范围更广泛

void clear(iostate state = goodbit)

用于清除文件流的错误状态,即重置文件流的状态标志位

二进制文件的读写

文件流类从istream类和ostream类分别继承了write()函数和read()函数,这两个函数可以用来读写二进制文件。

#include <iostream>
#include <fstream>
using namespace std;

struct Student
{
	char name[20];
	int age;
	char sex[5];

};
int main() {
	Student stu[3];
	cout << "请输入三名学生的信息(姓名 年龄 性别)" << endl;
	for (int i = 0; i < 3; i++) {
		cin >> stu[i].name >> stu[i].age >> stu[i].sex;
	}
	fstream fs("student.dat", ios::out | ios::binary);
	if (!fs) {
		cout << "文件打开失败";
		exit(0);
	}
	//写入文件
	for (int i = 0; i < 3; i++) {
		fs.write(reinterpret_cast<char *>(&stu[i]), sizeof(stu[i]));
		fs.flush();
	}
	fs.close();
	cout << "写入成功" << endl;
	fs.clear();
	fs.open("student.dat", ios::in | ios::binary);
	if (!fs) {
		cout << "文件打开失败";
		exit(0);
	}
	//读取文件
	Student s[3];
	for (int i = 0; i < 3; i++) {
		fs.read(reinterpret_cast<char *>(&s[i]), sizeof(s[i]));
		cout << s[i].name << s[i].age << s[i].sex << endl;
	}
	fs.close();
	
	return 1;
}

iostream不能用printf吗 iostream有没有printf_iostream不能用printf吗_10

每次读写一个结构体变量,由于read()函数和write()函数的第一个参数为char*类型,因此在传递参数时,需要调用reinterpret_cast<>运算符将Student结构体变量的地址转换成char*类型。

reinterpret_cast <new_type> (expression)

文件随机读写

在C语言中实现文件的随机读写要依靠文件位置指针,在C++中文件的随机读写也是通过移动文件位置指针完成的。
C++文件流类提供了设置文件位置指针的函数。ifstream类提供了tellg()函数、seekg()函数。

streampos tellg(); //tellg()函数用于返回文件位置指针的位置
istream& seekg(streampos);//文件位置指针从文件开头移动streampos长度的距离
istream& seekg(streamoff,ios::seek_dir);//指定参照位置情况下,位置指针移动streamoff长度的距离

参照位置

说明

ios::beg = 0

从文件开头开始移动

ios::cur = 1

从当前位置开始移动

ios::end = 2

从文件结尾开始移动

ofstream类同样提供了tellp()函数、seekp()函数用于移动文件位置指针,操作、含义都相同。

fstream fs("student.dat",ios::in|ios::binary);
cout << "当前文件指针位置:" << fs.tellp() << endl;
char c[10];
fs.read(c, sizeof(c));
cout << "读取内容:" << c << endl;
cout << "当前文件指针位置:" << fs.tellp() << endl;
fs.seekp(10,ios::cur);
cout<<"向后移动指针10长度"<< fs.tellp() << endl;
fs.close();

iostream不能用printf吗 iostream有没有printf_ios_11

字符串流

字符串流是以string对象为输入/输出对象的数据流,这些数据流的传输在内存中完成,因此字符串流也称为内存流。C++提供了istringstream、ostringstream和stringstream这三个类支持string对象的输入/输出。

stringstream类的一个典型用法就是将一个数字字符串转换成对应的数值。相比于C语言的数字和字符串转换函数,stringstream类具有模板亲和性,转换效率更高而且更安全。

#include <iostream>
#include <sstream>
#include <string>
using namespace std;

template<typename T>
T swapString(const string &str) {
	stringstream s(str,ios::in); //只读模式
	T t;
	s >> t;
	return t;
}
int main() {
	cout << "12的大小:" << sizeof("12") << endl;
	cout << "3.14的大小:" << sizeof("3.14") << endl;
	int num = swapString<int>("12");
	cout << num<<"转为int后的大小: " << sizeof(num) << endl;
	double n = swapString<double>("3.14");
	cout << n << "转为double后的大小: " << sizeof(n) << endl;
	return 1;
}

iostream不能用printf吗 iostream有没有printf_ci_12