# 流对象与文件操作

  • 程序建立一个流对象
    • 当程序与 外界环节 进行信息交流时,存在着两个对象,一个是程序中的对象,另一个是文件对象
    • 流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理 数据的流动
  • 指定这个流对象与某个文件对象建立连接
  • 程序操作流对象
  • 流对象通过文件系统对所连接的文件产生作用

# 提取与插入

  • 读操作在流数据抽象中被称为 (从流中) 提取
  • 写操作被称为 (向流中) 插入
类名说明包含文件
抽象流基类
ios流基类ios
输入流类
istream通用输入流类和其它输入流的基类istream
ifstream文件输入流类fstream
istringstream字符串输入流类sstream
输出流类
ostream通用输出流类和其它输出流的基类ostream
ofstream文件输出流类fstream
ostringstream字符串输出流类sstream
输入 / 输出流类
iostream通用输入 / 输出流类和其它输入 / 输出流的基类istream
fstream文件输入 / 输出流类fstream
stringstream字符串输入 / 输出流类sstream
流缓冲区类
streambuf抽象流缓冲区基类streambuf
filebuf磁盘文件的流缓冲区类fstream
stringbuf字符串的流缓冲区类sstream

# 预先定义的输出流对象

  • cout 标准输出
  • cerr 标准错误输出, 没有缓冲 ,发送给他的内容立即被输出
  • clog 类似 cerr , 但 有缓冲 ,缓冲区满时被输出

# 构造输出流对象

  • ofstream 类支持 磁盘文件 输出

  • 如果在构造函数中制定一个文件名,当构造这个对象时该文件是自动打开的

ofstream myFile("filename");
  • 可以在调用默认构造函数之后使用 open 成员函数打开文件
ofstream myFile; // 声明一个静态文件输出流对象
myFile.open("filename");  // 打开文件,使流对象与文件建立联系,关联
  • 在构造对象或用 open 打开文件时可以指定模式,默认存文本文件
ofstream myFile("filename",iso_base::out | ios_base::binary);

# 文件输出流成员函数

  • 与操作符等价的成员函数
  • 执行 非格式化 写操作的成员函数
  • 其它修改流状态且不同于操作符或插入运算符的成员函数

# 文件输出流成员函数

  • open 函数
    • 把流与一个特定的磁盘文件关联起来
    • 需要指定打开模式
  • put 函数
    • 把一个字符写到输出流中
  • write 函数
    • 把内存中的一块内容写到一个文件输出流中 (写 二进制 文件用)
  • seekptellp 函数
    • 操作文件流的 内部指针
    • seekp 写到什么位置标志
    • tellp 告诉文件位置,开始的字节数
  • close 函数
    • 关闭与一个文件输出流关联的磁盘文件
  • 错误处理函数
    • 在写到一个流时进行错误处理

# 向文本文件输出

# 插入运算符
  • 插入 ( << ) 运算符
    • 传送字节到输出流对象,为所有标准 C++ 数据类型预先设计
# 操作符 ( manipulator )
  • 插入运算符 与操作符一起工作
    • 控制输出格式
  • 很多操作符都定义在

ios_base 类中 (如 hex(),<iomanio>头文件(如setprecision()) )

  • 控制输出宽度
    • 在流中放入 setw 操作符或调用 width 成员函数为每个项指定输出宽度
  • setwwidth 仅影响紧随其后的输出项,但其它流格式操纵符保存有效指导发生改变
  • decocthex 操作符设置输入和输出的默认进制
#include <iostream>
using namespace std;
int main(void)
{
	double values[] = { 1.23,35.36,653.7,4358.24 ,124567899};
	for (int i = 0; i < 5; i++)
	{
		// 使用 width 控制输出宽度
		// 每个字符 10 个字节
		cout.width(10); // 影响其后的输出项,只影响一个
		cout << values[i] << endl;
	}
	return 0;
}
/*
	  1.23
	 35.36
	 653.7
   4358.24
1.24568e+08
*/
# 输出到文本
#include <fstream>
using namespace std;
int main(void)
{
	ofstream txtout("file1.txt");
	double values[] = { 1.23,35.36,653.7,4358.24 ,124567899 };
	for (int i = 0; i < 5; i++)
	{
		txtout.width(10);
		txtout <<  values[i] << endl;
	}
	txtout.close(); // 记得关闭
	return 0;
}

文本输出

# 一行多输出,宽度,对齐,精度
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(void)
{
	double values[] = { 1.23,35.36,653.7,4358.24 };
	string names[] = { "Zoot","Jimmy","AI","Stan" };
	for (int i = 0; i < 4; i++)
	{
		cout << setw(6) << names[i]
			<< setw(10) << values[i] << endl;
	}
	// 设置对齐方式
	cout << "设置对齐方式" << endl;
	for (int i = 0; i < 4; i++)
	{
		cout << setiosflags(ios_base::left) // 左对齐
			<< setw(6) << names[i]
			<< setw(10) << values[i] << endl;
	}
	// 输出精度
	cout << "控制输出精度" << endl;
	cout << setiosflags(ios_base::fixed);
	for (int i = 0; i < 4; i++)
	{
		cout << setiosflags(ios_base::left) // 左对齐
			<< setw(6) << names[i]
			<< setw(10) << values[i]
			<< resetiosflags(ios_base::left)// 清除左对齐设置
			<< setw(10) << setprecision(1) <<values[i]
			<<endl;
	}
	// 输出精度 scientific
	cout << "控制输出精度scientific" << endl;
	cout << setiosflags(ios_base::scientific);
	for (int i = 0; i < 4; i++)
	{
		cout << setiosflags(ios_base::left) // 左对齐
			<< setw(6) << names[i]
			<< resetiosflags(ios_base::left)// 清楚左对齐设置
			<< setw(10) << setprecision(1) << values[i]
			<< endl;
	}
	return 0;
}
/*
  Zoot      1.23
 Jimmy     35.36
	AI     653.7
  Stan   4358.24
设置对齐方式
Zoot  1.23
Jimmy 35.36
AI    653.7
Stan  4358.24
控制输出精度
Zoot  1.230000         1.2
Jimmy 35.4            35.4
AI    653.7          653.7
Stan  4358.2        4358.2
控制输出精度 scientific
Zoot  0x1.3ae147ae147aep+0
Jimmy 0x1.1ae147ae147aep+5
AI    0x1.46d999999999ap+9
Stan  0x1.1063d70a3d70ap+12
*/

# setiosflags 操作符

  • 头文件 iomanip
  • ios_base::前缀
  • setiosflags 不同于 widthsetw ,它的影响是持久的,直到 resetiosflags 重新恢复默认值时为止
  • setiosflags 的参数是该流的格式标志值,可用按位或 (|) 运算符就行组合
# setiosflags 参数

流的格式标识

  • ios_base::skipws 在输入中跳过空白 。
  • ios_base::left 左对齐值,用填充字符填充右边。
  • ios_base::right 右对齐值,用填充字符填充左边(默认对齐方式)。
  • ios_base::internal 在规定的宽度内,指定前缀符号之后,数值之前,插入指定的填充字符。
  • ios_base::dec 以十进制形式格式化数值(默认进制)。
  • ios_base::oct 以八进制形式格式化数值 。
  • ios_base::hex 以十六进制形式格式化数值。
  • ios_base::showbase 插入前缀符号以表明整数的数制。
  • ios_base::showpoint 对浮点数值显示小数点和尾部的 0 。
  • ios_base::uppercase 对于十六进制数值显示大写字母 A 到 F,对于科学格式显示大写字母 E 。
  • ios_base::showpos 对于非负数显示正号(“+”)。
  • ios_base::scientific 以科学格式显示浮点数值。
  • ios_base::fixed 以定点格式显示浮点数值(没有指数部分) 。
  • ios_base::unitbuf 在每次插入之后转储并清除缓冲区内容。

# 精度

  • 浮点数输出精度的默认值是 6 , 例如:3466.98
  • 改变精度: setprecision 操作符 (头文件 iomanip 中)
  • 如果不指定 fixed 或 scientific, 精度值表示有效数字位数
  • 如果设置了 ios_base::fixedios_base::scientific 精度值表示 小数点之后的位数

# 二进制文件流

  • 使用 ofstream 构造函数中的模式参数指定 二进制输出模式
  • 以通常方式构造一个流,然后使用 setmode 成员函数,在文件打开后改变模式;
  • 通过二进制文件输出流对象完成输出
#include <fstream>
using namespace std;
struct Date
{
	int mon, day, year;
};
int main(void)
{
	Date dt = { 6,10,92 };
	ofstream file("date.dat", ios_base::binary); // 二进制
	file.write(reinterpret_cast<char*>(&dt), sizeof(dt));
	file.close();
}

# 向字符串输出

将字符串作为输出流的目标,可以实现将其他数据类型转换为字符换的功能

# 字符串输出流

  • 用于构造字符串
  • 功能
    • 支持 ofstream 类除 openclose 外的所有操作
    • str函数 可以返回当前已构造的字符串
  • 典型应用
    • 将数值转换为字符串
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
/*
函数模版 toString 可以将・各种支持・"<<" 插入符类型的额对象转换为字符串
*/
template <class T>
inline string toString(const T& v)
{
	ostringstream os;  // 创建字符串输出流
	os << v;	// 将变量 v 的值写入字符串流
	return os.str();  // 返回输出流生成的字符串
}
int main(void)
{
	string str1 = toString(5);
	cout << str1 << endl;
	string str2 = toString(1.2);
	cout << str2 << endl;
	return 0;
}
/*
5
1.2
*/

# 输入流

  • tream 类最适合用于顺序文本模式输入, cin 是实例
  • ifstream 类支持磁盘文件输入
  • istringstram

# 构造输入流对象

  • 如果在构造函数中指定一个文件名,在构造该对象时该文件便自动打开。
ifstream myFile("filename");
  • 在调用默认构造函数之后使用 open 函数来打开文件。
ifstream myFile;// 建立一个文件流对象
myFile.open("filename");
  // 打开文件 "filename”
  • 打开文件时可以指定模式
ifstream myFile("filename", ios_base::in | ios_base::binary);

# 使用 提取运算符 从文本文件输入

  • 提取运算符 (>>) 对于所有标准 c++ 数据类型预先设计
  • 是从一个输入流对象获取直接最容易的方法
  • ios 类中很多操纵符都可以应用于输入流,但是只有少数几个对输入流对象具有实际影响,最重要 的是进制操作符 dec十进制oct八进制hex十六进制

# 输入流相关函数

  • open函数 把该流与一个特定磁盘文件相关联。
  • get函数 的功能与提取运算符 (>>) 很相像,主要的不同点是 get 函数在读入数据时包括 空白字符
  • getline 的功能是从输入流中读取多个字符,并且允许指定输入终止字符,读取完成后,从读取的内容中删除终止字符。
  • read成员函数 从一个文件读字节到一个指定的内存区域,由长度参数确定要读的字节数。当遇到文件结束或者在文本模式文件中遇到文件结束标记字符时结束读取。
  • seekg函数 用来设置文件输入流中读取数据位置的指针。
  • tellg函数 返回当前文件读指针的位置。
  • close函数 关闭与一个文件输入流关联的磁盘文件。
/* 
get 函数应用
*/
#include <iostream>
using namespace std;
int main(void)
{
	char ch;
	// 从键盘中输入,然后输出
	while ((ch = cin.get()) != EOF) 
	{
		cout.put(ch);
	}
	//ctrl+z 结束
	return 0;
}

/*
为输入流指定一个终止字符
*/
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
	string line;
	cout << "Type a line terminated by '\t'" << endl;
	getline(cin, line, '\t');
	cout << line <<  endl;
}
/*
从文件中读一个二进制记录到一个结构体
*/
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
struct SalaryInfo
{
	unsigned id;
	double salary;
};
int main(void)
{
	SalaryInfo employee1 = { 600001,8000 }; // 声明结构体
	ofstream os("payroll", ios_base::out | ios_base::binary); // 文件输出流,二进制类型
	// 字符转换,大小
	os.write(reinterpret_cast<char*>(&employee1), sizeof(employee1)); // 将结构体写入文件输出流
	os.close();
	ifstream is("payroll", ios_base::in | ios_base::binary); // 读二进制文件。输入方式,二进制文件
	if (is)
	{
		SalaryInfo employee2;
		is.read(reinterpret_cast<char*>(&employee2),sizeof(employee2));
		cout << employee2.id << " " << employee2.salary << endl;
	}
	else
	{
		cout << "ERROR:Cannot open file 'payroll'" << endl;
	}
	is.close();
	return 0;
}

/*
用 seekg 函数设置位置指针
*/
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main(void)
{
	int values[] = { 3,7,0,5,4 };
	ofstream os("integers", ios_base::out | ios_base::binary);
	os.write(reinterpret_cast<char*>(values), sizeof(values));
	os.close();
	ifstream is("integers", ios_base::in | ios_base::binary);
	if (is)
	{
		is.seekg(3 * sizeof(int));// 跳跃三个整数位置
		int v;
		is.read(reinterpret_cast<char*>(&v), sizeof(int));
		cout << "The 4th integer in the file 'integers' is " << v << endl;
	}
	else
	{
		cout << "ERROR :Cannot open file 'integers'" << endl;
	}
	return 0;
}

/*
读入一个文件并显示出其中 0 元素的位置
*/
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main(void)
{
	ifstream file("integers", ios_base::in | ios_base::binary);
	if (file)
	{
		while (file)  // 读到文件尾 file 为 0
		{
			//tellg 函数返回当前文件读指针的位置
			streampos here = file.tellg();
			int v;
			file.read(reinterpret_cast<char*>(&v), sizeof(int));
			if (file && v == 0)
				cout << "Position:\t" << here << "\tis 0" << endl;
		}
	}
	else
	{
		cout << "ERROR:Cannot open file \"integers\"." << endl;
	}
	file.close();
}

# 从字符串输入

将字符串作为文本输入流的源,可以经字符串转换为其他数据类型

# 字符串输入流 ( istringstream )
  • 用于从 字符串读取数据
  • 在构造函数中设置要读取的字符串
  • 功能
    • 支持 ifstream 类的除 open,close 外的所有操作
  • 典型应用
    • 将字符串转换为数值
// 用 istringstream 将字符串转换为数值
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
template <class T>
inline T fromString(const string& str) 
{
	istringstream is(str);	// 创建输入字符串流
	T v;
	is >> v;				// 从输入字符串流中读取变量 v
	return v;				// 返回变量 v
}
int main() 
{
	int v1 = fromString<int>("5");
	cout << v1 << endl;
	double v2 = fromString<double>("1.2");
	cout << v2 << endl;
	return 0;
}
# 重要输入 / 输出流
  • iostream 对象可以是数据的源或目的
  • 两个重要的 I/O 流类都是从 iostream 派生,他们是 fstream 和 stringstream
    • 这些类继承了前面描述的 istream 和 ostream 类功能
# fstream 类
  • fstream 类支持磁盘文件输入和输出
  • 可构造 fstream 实现从一个特定磁盘文件读并谢大鹏磁盘 文件
  • 一个 fstream 对象是 有两个逻辑 子流的单个流,两个子流一个用于输入,另一个用于输出
# stringstream 类
  • stringstream 类支持面向字符串的输入和输出
  • 可以用于对同一个字符串的内容交换读写 ,同样是由两个逻辑子流构成

# getline 读取文本练习

#include <iostream>
#include <fstream> // 文本 输出
#include <string> // 引用字符串
#include <iomanip>  // 对齐操作符头文件
#include <istream>  // 输入流函数
using namespace std;
int main(void)
{
	// 打开文件,默认文本形式
	ofstream textout("test.txt",ios_base::out | ios_base::binary);
	string hello = "hello test\nhello second!";
	//textout.width (20);  // 文字占 20 个字节
	textout 
		//<< setiosflags (ios_base::right)  // 右对齐
		<<hello<<endl;
	textout.close();
	// 读取文章内容
	ifstream myFile("test.txt", ios_base::in | ios_base::binary);
	string out;
	while (myFile) // 使用 while 读取一行一行的读入
	{
		// 使用 getline 读取文件中字符,
		//getline 函数原型 getline (std::cin,string s,char ch),
		// 表示以字符 ch 来结束字符串的读入。
		getline(myFile, out);
		cout << out << endl;
	}
	/*else
	{
			cout << "ERROR:Cannot open file 'text.txt'" << endl;
	}*/
	myFile.close();
	return 0;
}

C++ 参考文档[1]


  1. http://www.cplusplus.com/reference/ ↩︎