C++中的I/O
遗忘点
对于各个in,out对象,凡是>> 操作,只要是读不到东西,都是返回0.
而且都是遇到空格就停止了。
I/O操作,是针对内存而言。
是对内存中的数据进行input和output。
这将是之后和文件I/O很多人分不清read,write等等到底是读还是写迷茫之处的根源。
示例:
cin:console in的意思。首先确定是个in,相对谁?所有I/O都是相对内存的。所以是in到内存中去,来自哪?cin的c告诉你了呀,是console。
其实,所有的ostream对象,都是把数据从内存中拿出来,输出去。
针对文件的ostream不就是把内存中的数据从内存中拿出来output到文件中吗
针对console的ostream(cout)不就是把内存中的数据放到screen上吗
针对字符串buffer的ostream不就是把内存中的数据放入一个buffer中吗。
istream同理。是那些来源in到内存中去。
根据对象属于istream还是ostream来判断是读入还是输出。(相对M)
控制台I/O
-
可以参考C语言的文件相关函数。这里是C++,不会再赘述,只会罗列。
常用的freopen()一般改成对文件的io非常方便。(竞赛+非工程) -
重载>> <<对对象可以实现I/O
-
其他的罗列如下:
fopen
in:
cin
setw(输入字符的最大个数)
getchar
gets
scanf (正则)
sscanf
对文件:
fgetc
fgets
fscanf
fread
out:
cout
setprecision(浮点数小数点后数字个数(ios::scientific/ios:fixed)/有效数字个数(自动/默认方式))
setiosflags(ios::scientific/ios:fixed/default) 设置输出格式
resetiosflags(ios::scientific/ios:fixed/default) 取消设置输出格式
cout<<string/char * 输出字符串
cout<<(void *) string/char * 输出指针的内容(地址)
cout<<*char * 输出str[0]
clog
cerr
putchar
puts
printf
sprintf
对文件:
fputc
fputs
fprintf
fwrite(二进制)
feof 常用while(!feof(fp)){…}
fclose
fflush 清空缓冲区 凡是和flush相关的都是清空缓冲区或者立即输出不过缓冲区的。
随机访问:
fseek
ftell
文件I/O
这里是上课老师主要讲的C++part的对文件的I/O对象
ios派生出
istream(控制台输入)和ostream(控制台输出)
前者派生出
- ifstream 文件输入
- istrstream 字符串输入
后者派生出 - ofstream 文件输出
- ostrstream 字符串输出
而iostream这个子类时由istream和ostream多继承而来,实现了存和取
它派生了两个重要子类 - fstream 可以对file存和取
- strstream 可以对字符串变量存和取
ostream对象常用的成员函数
ostream & ostream::put(char ch); //单个字符
ostream & ostream::write(const char *p,int count); //输出p指向空间中count个字节
istream对象常用的成员函数
istream & istream::get(char &ch); //单输入一个字符到内存中名为ch的变量空间中
istream & istream::read(const char *p,int count); //读入count个字节到p指向的M中
istream & istream::getline(char *p,int count,char delim='\n'); //向一个字符串p处直到输入了count-1个字符 或者就是遇到了\n结束读入到p中
//getline如果没有读到字符会返回false可判断文件是否结束
char str[10];
cin.getline(str,10);//从键盘输入9个字符 可以包含空格,直到遇到第十个字符(补\0)或遇到\n
判断操作是否成功:
bool ios::fail();
//尤其是对文件指针移动的时候很容易飘逸越界等等,需要用fail函数判断
注意重载<< >>来输出A类的私有成员时,必须在A类中声明对operator << >>的重载是友元。而且重载的返回值必须是引用类型,否则无法实现连续输出。而且父类的这个重载,对于子类像一些文件fstream都是可以接着用的。肥肠的方便。
cout,cin返回的都是xstream对象。
cout<<A<<B;这种,如果对C类对象A,B重载,如果返回仅仅是ostream而不是ostream & 在先输出A之后,就无法再输出B。因为返回的那个ostream(重载的)对象调用后就消失了,传引用就是保证是对这个对象真真切切本身做了修改,而不是它的拷贝构造。
总之,连续操作必须返回值传递引用
如果要用间接访问,动态绑定。需要对父类响应重载的<<,>>函数声明成虚函数即可。
i/ostream对象的具体使用
ostream myout("data.dat",ios::out|ios::binary); //如此和文件建立关联
if (!myout) exit(-1) ; //说明没有成功创建这个和data.txt关联起来的文件输出对象
myout.write((char*) &student,sizeof(student));//char *转化为字节。对一个struct 为student类型的结构体一次向文件中out一个学生信息元素。而且是二进制形式。
myout.close();
int ,x,y;
ifstream myin("data.txt",ios::in);//从文件读数据in到M
if (!myin) exit(-1);
myin>>x>>y;
or
int ,x,y;
ifstream myin("data.dat",ios::in|ios::binary);//从文件读数据in到M
if (!myin) exit(-1);
myin.read((char*)&x,sizeof(x));
//以二进制的方式读入数据到内存中
if (myin.eof()!=0) myin.close();//说明已经读入结束,可以关闭文件了
int ios::eof()
判断文件是否已经读入结束
返回非0(true)就是已经读入结束。
随机存取
fstream类,随机性需要对指针进行调度
fstream casual_io("data.dat",ios::in|ios::out);
既支持in也支持out
随机性:
istream & istream::seekg(绝对位置);
istream & istream::seekg(offset,相对位置);
streampos istream::tellg();//获得指针位置
ostream & ostream::seekp(绝对位置);
ostream & ostream::seekp(offset,相对位置);
streampos ostream::tellp();//获得指针位置
相对位置:
- ios::beg 开头
- ios::cur 当前位置
- ios::end 文件末尾
一些实例(其实是老师布置的天杀的作业)(过几天写完了上传)
- 编写一个拷贝程序,它能把一个文件中的内容赋值到另一个文件中
#include<bits/stdc++.h>
using namespace std;
int main() {
ifstream myin("data1.txt",ios::in);
ofstream myout("data2.txt",ios::out);
char filecontent[500];
while(!myin.eof()) {
myin.getline(filecontent,1000);
myout<<filecontent;//一次读入一个不含空白符的内容
}
cout<<"拷贝结束\n";
return 0;
}
- 编写一个程序,统计一个文本文件的行数
#include<bits/stdc++.h>
using namespace std;
const int MAX_LINE = 1000 ;
int main() {
const char *filename = "enfile.txt";
ifstream myin(filename,ios::in);
int line=0;
char s[MAX_LINE];
while(myin.getline(s,MAX_LINE)!=false){
line++;
}
cout<<filename<<"共有"<<line<<"行\n";
return 0;
}
- 编写一个通讯录的IO程序,该程序从键盘输入通讯录,然后把它保存到文件中,通讯录的内容包括:序号,姓名,单位,电话。要求程序中,通讯录是一个类,通过重载<< >>来实现对通讯录的输入和输出.
#include<bits/stdc++.h>
using namespace std;
/*
通讯录的内容包括:序号,姓名,单位,电话。要求程序中,通讯录是一个类
cin
myout到file
*/
class AddressBook{
private:
string seq;
string name;
string company;
string tel;
bool init;
public:
bool getinit(){
return init;
}
AddressBook():init(false){
}
friend istream& operator >> (istream& in,AddressBook &ab); //输入符
friend ostream& operator << (ostream& out,AddressBook &ab); //输出符
};
ostream& operator << (ostream& out,AddressBook &ab){
out<<"序号为"<<ab.seq<<"名为"<<ab.name<<"的公司是"<<ab.company<<",电话是:"<<ab.tel<<endl;
return out;
}
istream& operator >> (istream& in,AddressBook &ab){
cout<<"请输入序列号(停止输入则输入-1):\n";in>>ab.seq;
if (ab.seq=="-1"){
ab.init = false;
return in;
}
cout<<"请输入姓名:\n";in>>ab.name;
cout<<"请输入公司名称:\n";in>>ab.company;
cout<<"请输入电话号码:\n";in>>ab.tel;
ab.init = true;
cout<<"输入完成\n";
return in;
}
int main() {
AddressBook msg;
ofstream myout("addressbook.txt",ios::app);
cin>>msg;//此时msg中的init就是true,可以一直输入
while(msg.getinit()){
myout<<msg;
cin>>msg;
}
cout<<"已经全部输入到文件\n";
return 0;
}
- 用文本文件保存该例下的学生信息
实例如下:
#include<bits/stdc++.h>
using namespace std;
enum Sex { MALE, FEMALE };
struct Date {
int year;
int month;
int day;
};
enum Major {
MATHEMATICS,PHYSICS,CHEMISTRY,COMPUTER,GEOGRAPHY,
ASTRONOMY,ENGLISH,CHINESE,PHILOSOPHY
};
struct Student
{
char id[11];
char name[9];
Sex sex;
Date birth_date;
char birth_place[40];
Major major;
};
int main() {
FILE* fp = fopen("student.dat", "wb");
if (fp == NULL) {
cout << "打开文件失败\n";
exit(-1);
}
Student st;
cout << "请输入学号,姓名,性别,出身日期(年,月,日),出生地和专业(以学号为'E'结束):\n";
scanf("%10s", st.id);
while (st.id[0] != 'E') {
//读入个信息到st中
cin >> st.name;
cin >> st.sex;
cin >> st.birth_date.year >> st.birth_date.month >> st.birth_date.day >> st.birth_place;
cin>> st.major;
fwrite(&st, sizeof(st), 1, fp); //将st的值输出到文件(二进制形式)
scanf("%10s", st.id);
}
fclose(fp);
return 0;
}
如下:
#include<bits/stdc++.h>
using namespace std;
enum Sex { MALE, FEMALE };
struct Date {
int year;
int month;
int day;
};
enum Major {
MATHEMATICS,PHYSICS,CHEMISTRY,COMPUTER,GEOGRAPHY,
ASTRONOMY,ENGLISH,CHINESE,PHILOSOPHY
};
struct Student
{
char id[11];
char name[9];
Sex sex;
Date birth_date;
char birth_place[40];
Major major;
};
int main() {
FILE* fp = fopen("student.txt", "w+");
if (fp == NULL) {
cout << "打开文件失败\n";
exit(-1);
}
Student st;
cout << "请输入学号(以学号为'E'结束):\n";
scanf("%10s", st.id);
while (st.id[0] != 'E') {
//读入个信息到st中
fprintf(fp,"%10s",st.id);
cout<<"name:";
cin >> st.name;
fprintf(fp,"%s",st.name);
int gender;
cout<<"性别(0男1女):";
scanf("%d",&gender);
if (gender==0){
fprintf(fp," 性别:男");
}
else if (gender==1){
fprintf(fp," 性别:女");
}
else{
printf("不男不女,默认不是人类\n");
exit(-1);
}
st.sex = (Sex)gender;//枚举的输入
cout<<"出生年";
cin >> st.birth_date.year ;
cout<<"月";
cin>> st.birth_date.month ;
cout<<"日" ;
cin>> st.birth_date.day;
cout<<"出生地点:";
cin >> st.birth_place;
fprintf(fp," 出生于%d年%d月%d日,%s",st.birth_date.year, st.birth_date.month, st.birth_date.day , st.birth_place);
int mj;
cout<<"专业(输入0~8数字):";
scanf("%d",&mj);
if (mj==0){
fprintf(fp,"MATHEMATICS");
}
else if (mj==1){
fprintf(fp,"PHYSICS");
}
else if (mj==2)
fprintf(fp,"CHEMISTRY");
else if (mj==3) fprintf(fp,"COMPUTER");
else if (mj==4) fprintf(fp,"GEOGRAPHY");
else if (mj==5) fprintf(fp,"ASTRONOMY");
else if (mj==6) fprintf(fp,"ENGLISH");
else if (mj==7) fprintf(fp,"CHINESE");
else if (mj==8) fprintf(fp,"PHILOSOPHY");
else fprintf("没有标准输入,属于被退学的孤儿");
st.major = (Major)mj;
fprintf(fp,"\n");
cout<<"学号:";
scanf("%10s", st.id);
}
fclose(fp);
return 0;
}
- 从键盘读入一堆图形信息(我还以为是OpenGL的,吓死我了)
#include<bits/stdc++.h>
using namespace std;
//定义三个图形
class line {
double beginx;
double endx;
double beginy;
double endy;
public:
double length() {
return sqrt((beginx-endx)*(beginx-endx)+(beginy-endy)*(beginy-endy));
}
friend ostream &operator << (ostream &out,line& l);
friend istream &operator >> (istream &in,line& l);
};
ostream &operator << (ostream &out,line &l) {
out<<"begin corordinate:("<<l.beginx<<","<<l.beginy<<"),"<<"end corordinate:("<<l.endx<<","<<l.endy<<") "<<"length:"<<l.length()<<endl;
return out;
}
istream &operator >> (istream &in,line &l) {
cout<<"请依次输入线的始末坐标(先x,后y)\n" ;
//先输入第一个坐标的x,y 再第二个
in>>l.beginx>>l.beginy>>l.endx>>l.endy;
}
class Round{
double x,y;
double r;
public:
friend ostream &operator << (ostream &out,Round &l);
friend istream &operator >> (istream &in,Round &l);
};
ostream &operator << (ostream &out,Round &l){
out<<"center corordinate:("<<l.x<<","<<l.y<<"),"<<"radius:"<<l.r<<endl;
return out;
}
istream &operator >> (istream &in,Round &l){
cout<<"请依次输入圆的圆心坐标(先x,后y)再输入半径\n" ;
in>>l.x>>l.y>>l.r;//依次输入圆心坐标和半径
return in;
}
class rectangle{
double x1,y1;
double length,width;
public:
friend ostream &operator << (ostream &out,rectangle &l);
friend istream &operator >> (istream &in,rectangle &l);
} ;
ostream &operator << (ostream &out,rectangle &l){
out<<"first corordinate:("<<l.x1<<","<<l.y1<<"),"<<"length:"<<l.length<<" width:"<<l.width<<endl;
return out;
}
istream &operator >> (istream &in,rectangle &l){
cout<<"请依次输入长方形的一个坐标(先x,后y)再输入长度和宽度\n" ;
in>>l.x1>>l.y1>>l.length>>l.width;
}
int main() {
line l1;
Round r1;
rectangle re1;
cin>>l1>>r1>>re1;
// cout<<l1<<r1<<re1<<endl;
// ifstream filein("GraphicInfo.txt",ios::in) ;
ofstream fileout("GraphicInfo.txt",ios::out);
// filein>>l1>>r1>>re1;
fileout<<l1<<r1<<re1;
return 0;
}
- 从上一题保存的图形文件中读入图形信息,并以某种方式把他们输出到显示器
#include<bits/stdc++.h>
using namespace std;
#define MAX_LINE 1000
//定义三个图形
class line {
double beginx;
double endx;
double beginy;
double endy;
public:
double length() {
return sqrt((beginx-endx)*(beginx-endx)+(beginy-endy)*(beginy-endy));
}
friend ostream &operator << (ostream &out,line& l);
friend istream &operator >> (istream &in,line& l);
};
ostream &operator << (ostream &out,line &l) {
out<<"LINE:begin corordinate:("<<l.beginx<<","<<l.beginy<<"),"<<"end corordinate:("<<l.endx<<","<<l.endy<<") "<<"length:"<<l.length()<<endl;
return out;
}
istream &operator >> (istream &in,line &l) {
cout<<"请依次输入线的始末坐标(先x,后y)\n" ;
in>>l.beginx>>l.beginy>>l.endx>>l.endy;
}
class Round{
double x,y;
double r;
public:
friend ostream &operator << (ostream &out,Round &l);
friend istream &operator >> (istream &in,Round &l);
};
ostream &operator << (ostream &out,Round &l){
out<<"ROUND:center corordinate:("<<l.x<<","<<l.y<<"),"<<"radius:"<<l.r<<endl;
return out;
}
istream &operator >> (istream &in,Round &l){
cout<<"请依次输入圆的圆心坐标(先x,后y)再输入半径\n" ;
in>>l.x>>l.y>>l.r;
return in;
}
class rectangle{
double x1,y1;
double length,width;
public:
friend ostream &operator << (ostream &out,rectangle &l);
friend istream &operator >> (istream &in,rectangle &l);
} ;
ostream &operator << (ostream &out,rectangle &l){
out<<"RECTANGLE:first corordinate:("<<l.x1<<","<<l.y1<<"),"<<"length:"<<l.length<<" width:"<<l.width<<endl;
return out;
}
istream &operator >> (istream &in,rectangle &l){
cout<<"请依次输入长方形的一个坐标(先x,后y)再输入长度和宽度\n" ;
in>>l.x1>>l.y1>>l.length>>l.width;
}
int main() {
line l1;
Round r1;
rectangle re1;
cin>>l1>>r1>>re1;
ofstream fileout("GraphicInfo.txt",ios::out);
fileout<<l1<<r1<<re1;
cout<<"stored all infomation into the file named GraphicInfo.txt!"<<endl<<endl;
ifstream filein("GraphicInfo.txt",ios::in) ;//第六题的内容 读出后显示
line l2;
Round r2;
rectangle re2;
while(!filein.eof()){
char read[MAX_LINE];
filein.getline(read,MAX_LINE);
cout<<read<<endl;
}
cout<<"ALL GRAPHIC MESSAGE OUT\n";
return 0;
}
- 读取一个英文的文本文件,统计文本文件中的单词的词频,按照词频从大到小依次输出单词和词频。
/*
读取一个英文的文本文件,统计文本文件中的单词的词频,按照词频从大到小依次输出单词和词频。
*/
#include<bits/stdc++.h>
using namespace std;
int main() {
ifstream myin("enfile.txt",ios::in);//in到enfile.txt中
unordered_map<string,int> mp;
while(!myin.eof())
{
string temp;
myin >> temp;
mp[temp]++;
}
for(pair<string,int> i:mp){
cout<<(i.first)<<"出现了"<<(i.second)<<"次\n";
}
return 0;
}