您的位置:首页 > 编程语言 > C语言/C++

[置顶] C了个++:01 - C++的输入、输出和文件

2016-10-01 09:39 344 查看
简单总结梳理了C++中有关文件输入输出的知识,并添加程序实例(实例见最后)

例程2:2016年华为软件编程大赛文件(topo.csv、demand.csv、result.csv)的输入输出(删减)


涉及知识:类、函数重载、模板、多重继承、流操作、缓冲区、控制符和格式化常量、类型转换

学习目的:文本文件输入输出、控制输出格式

使用的类:iostream(标准输入输出类)、fstream(文件输入输出类)、sstream(string字符串输入输出类)

流操作:(C++把输入输出看作字节流,通过对字节流对象进行操作来对数据做相应的输入输出处理)

流是由字符字节(char)组成的数据,流操作(方法)的本质是类型转换操作
将流与程序关联起来(声明输入流/输出流对象)
将流与文件关联起来(将输入流/输出流对象与文件关联起来,调用成员函数open(char*)方法)
以上两个关联可以通过声明初始化一步完成,流的使用方法同标准的流cin/cout

缓冲区:(内存块,设备与程序之间的临时存储工具,帮助匹配两者不同的传输速率)

键盘输入时,通常是按下回车键时,刷新输入缓冲区
屏幕输出时,通常是发送换行符时,刷新输出缓冲区;有输入到来时,也可能会刷新输出缓冲区
使用控制符endl和flush

继承关系:作图

ios_base类(流的一般特征:格式化常量等)    --->    ios类(包括一个指向streambuf对象的指针)    --->    istream类/osteam类(方法)    --->    iostream类    --->    fstream类  
 --->    ifstream类/ofstream类
sstream类的继承关系流程同fstream类    --->    istringstream类/ostringstream类
streambuf类(管理输入/输出缓冲区的内存的类)
创建类对象,会打开一个流,并自动创建一个属于各自对象的缓冲区;包含iostream头文件会自动创建8个流对象(cin/cout/cerr/clog)(4个用于窄字符流,4个用于宽字符流)和一些对象代表流(它是与流特性相关的数据成员)
其它,将iostream类在std名称空间中,istream类和ostream类都是模板char具体化的typedef

输出格式化:

cout<<输出、ostream & put(char)、ostream & write(char*,int),类型转换为char以文本字符格式输出(参数为普通基本类型或const的char指针或void*),另外write()不会遇到空字符停止打印字符
ios_base类中的成员函数setf()方法(可调整单个格式标记信息)两个原型:fmtflags setf(fmtflags);  fmtflags setf(fmtflags,fmtflags);  (fmtflags是bitmask类型),该方法需结合使用格式化常量;fmtflags类型也是在ios_base类中定义的;另外,unsetf()方法原型:void unsetf(fmtflags);
标准控制符:计数系统控制(dec/oct/hex:basefield)数字显示控制(fixed/scientific:floatfield)对齐控制(left/right/internal:adjustfield)等等
3个最常用的控制符(头文件iomanip):setprecision(int)、setfill(char)、setw(int)分别设置精度、填充字符、字段宽度,相对于precision(int)、fill(char)、int width(int)使用更方便
控制符(运算符函数重载)可用cout语句进行连接,控制符是函数,但不是成员函数,不能通过对象调用使用;控制符位于名称空间std中
默认显示模式的精度是总位数,fixed/scientific显示模式的精度是小数位数
cout.setf(ios_base::showpoint);可显示末尾的0,显示的多少取决于显示模式和精度,显示的数字位数与数字被存储时的精度没有任何关系

输入:(给程序提供数据)

cin>>输入,格式化输入函数(参数为基本类型引用或char指针),跳过空白(空格、换行符、制表符)
ios_base类中数据成员流状态(eofbit/badbit/failbit/goodbit)iostate类型(也是bitmask类型)是在ios_base类中定义的,这3个状态位都为0时,说明一切正常
常用的设置流状态方法:good()、clear(iostate s=0)(无参可以用于重新打开输入)、setstate(iostate s);设置流状态位有一个非常重要的后果,流将对后面的输入或输出关闭,直到位被清除
非格式化输入成员函数istream & get(char &)、int get(void)单字符输入,不跳过空白
非格式化输入成员函数get(char*,int+1,char)、getline(char*,int+1,char)读取字符串进行输入,不跳过空白;第三个参数省略的话,默认将换行符用作分界字符;读取最大数目的字符或分界字符后为止;两者的主要区别是是否保留分界符,getline(char*,int+1,char)不保留分界符
非预期设置failbit,流被破坏设置badbit,文件尾设置eofbit;文件尾符号常量EOF(头文件iostream中定义),cin.get(ch)遇文件尾转换为false  并设置failbit,ch=cin.get()遇到文件尾输出EOF的值;文件尾或空行(即没有读取任何字符),get(char*,int+1,char)都会设置failbit,文件尾(或特殊空行)或读取最大数目的字符(且行中还有字符)时,会让getline(char*,int+1,char)设置failbit;while(getline(cin,str)&&str.size()>0){}空行处理方法
cin.ignore(int,'\n');可用于删除行中剩余的字符;char cin.peek();(==get(char)+putback(char))可用于查看下一个字符,但不抽取,可以用于多种条件(多个分界符)同时分割字符串;read()不会添加空字符,对应于write()
其它,getline(cin/fin/instr,string str,char ch)很方便

文件关联:

包含头文件fstream就可以,不必包含iostream,因为继承关系,但cin/cout/cerr对象的使用需要iostream头文件
以默认模式打开文件进行输出将自动把文件的长度截短为零,即删除已有内容
输入输出流对象过期时(即程序终止时),文件关联自动关闭,或用close()方法类似显式关闭;换其它文件进行关联需要显式使用close()方法;没有打开文件的话,不需要进行关闭关联,因为没关联上
关闭关联并不会删除流对象,则可以将流重新关联同一文件或另一文件,可能会需要cin.clear()方法重新打开输入,这取决于将文件与ifstream对象关联起来时,是否自动重置流状态,使用cin.clear()方法是无害的;关闭文件关联会刷新缓冲区
成员函数open(char*)方法以及ofstream的构造函数和ifstream的构造函数,参数指向char的指针(地址)是C-风格字符串,有必要将以string对象为文件名的字符串使用c_str()方法来转换为C-风格的字符串

打开一个不存在的文件进行输入时,将设置failbit,一种更好的检查文件是否被打开的方法is_open()
多文件处理策略取决于是同时处理使用还是依次处理使用,少开一些流会节省计算机资源
命令行参数(指定文件)int main(int argc,char* argv[])注意[]在argv后面,即第二个参数为char(* argv)[],argc是命令行参数个数,char(* argv)[]是一个指向char的指针数组(地址数组)

文件模式:(描述文件如何被使用:读、写、追加)

文件流的构造函数和i/ofstream open(char*,openmode mode=ios_base::in/out|trunc)方法,第二参数指定文件模式;注意,fstream类不提供默认的文件模式值,创建该对象必须显式提供第二参数
openmode类型与fmtflags类型和iostate类型一样,都是一种bitmask类型,在ios_base中定义;文件模式常量(in/out/ate/app/trunc/binary);文件模式错误能够被is_open()方法检测出来

内核格式化:(负责程序和string对象的I/O)

iostream族负责程序与终端之间的I/O;fstream族负责程序与文件之间的I/O;sstream族负责程序与string对象之间的I/O;接口使用方法相同
string对象本质是文本文件,所以所对应的流操作依然是类型转换,也叫格式化信息操作(内核格式化)
ostringstream中成员函数string str();返回一个被初始化为缓冲区内容的字符串对象,该方法可以“冻结”该对象
getline(cin/fin/instr,string,char)很方便,因为string类很好用
string字符串关联,istringstream流对象可以使用string对象进行初始化,如istringstream instr(str);

例程1:实现命令行参数读取文件,并对文件中的字符数进行统计求和
#include<fstream>
#include<iostream>			// for cerr/cout
//#include<cstdlib>			// for exit()

int main(int argc,char* argv[])		// 命令行参数,argv[i]是第 i 个指向 char 的指针(地址)
{
using namespace std;

if (argc == 1)			// quit if no arguments
{
cerr << "Usage: " << argv[0] << " filename[s]\n";
exit(EXIT_FAILURE);
}

ifstream fin;			// 开一个文件输入流
long count;
long total = 0;
char ch;

for (int i = 1;i < argc;i++)
{
fin.open(argv[i]);			// 关联第 i 文件
cout << i << " | " << argc << "   ";
if (!fin.is_open())			// 没有打开就不用使用close()
{
cerr << "Can't open " << argv[i] << endl;
fin.clear();			// 重新打开输入
continue;
}
count = 0;
while (fin.get(ch))count++;		// 统计文件中的字符数
cout << count << " character in " << argv[i] << endl;

total += count;
fin.clear();				// 重新打开输入
fin.close();				// 换文件需要先断开之前的文件  disconect file
}
cout << total << " charaters in all files.";

return 0;
}


例程2:2016年华为软件编程大赛文件(topo.csv、demand.csv、result.csv)的输入输出(删减)

#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<iomanip>		// for setw() setfill()

int main()//int argc,char* argv[])					// 命令行参数
{
using namespace std;

ifstream file_topo("F:\\topo.csv");//argv[1]);			// 关联 topo.csv 文件
string topo_line;
string topo_num[4];
int top_num[4];

if (file_topo.good())						// check
{
while (getline(file_topo,topo_line))			// read one line
{
istringstream strl_topo(topo_line);		// 将每一行初始化一个字符串输入流对象
for (int i = 0;i < 4;i++)
{
getline(strl_topo,topo_num[i],',');	// 按“,”进行分割
top_num[i] = atoi(topo_num[i].c_str());	// 转换为 int 类型,为之后比较大小
cout << setw(2) << setfill('0') << top_num[i] << " ";	// 格式化输出
}
cout << endl;
}
}
cout << "*********************************" << endl;
file_topo.close();
//file_topo.clear();

ifstream file_demand("F:\\demand.csv");//argv[2]);		// 关联 demand.csv 文件
string demand_line;
string demand_sec[3];
string demand_num[52];
int num_len = 0;

if (file_demand.good())
{
if (getline(file_demand,demand_line))
{
istringstream strl_demand(demand_line);
for (int i = 0;i < 3;i++)
{
getline(strl_demand,demand_sec[i],',');
}
istringstream strsec_demand(demand_sec[2]);
int i = 2;
while (getline(strsec_demand,demand_num[i],'|'))
{
i++;
}
num_len = i;
}
}
int* dem_num = new int[num_len];								// 动态数组
dem_num[0] = atoi(demand_sec[0].c_str());cout << dem_num[0] << " ";
dem_num[1] = atoi(demand_sec[1].c_str());cout << dem_num[1]
944d
<< " ";
for(int i = 2;i < num_len;i++)
{
dem_num[i] = atoi(demand_num[i].c_str());cout << dem_num[i] << " ";
}
cout << endl << "*********************************" << endl;
file_demand.close();
//file_demand.clear();

ofstream file_result;					// 关联 result.csv 文件
file_result.open("F:\\result.csv",ios::out|ios::trunc);	//argv[3],ios::out|ios::trunc);
file_result << setw(2) << setfill('0') << dem_num[0];
for(int i = 1;i < num_len;i++)
{
file_result << "|" << setw(2) << setfill('0') << dem_num[i];
}
file_result.close();
//file_result.clear();

return 0;
}


本文总结自《C++ primer plus》(第六版中文版)第十七章:输入、输出和文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: