c++游戏小技巧12:输入输出流(存读档超全版)

目录

1.前言

2.输入/输出概念

3.流的概念

4.正文

1.标准I/O流

1.get()函数

 2.getline()函数

3.read()函数 

4.ignore()函数

5.gcount()函数

6.peek()函数

7.putback()函数

8.istream集合栗子

9.put()函数

10.write()函数

11.ostream集合栗子

2.文件I/O流

1.流的关闭

2.缓冲区类型

3.设置缓冲区属性

4.缓冲区清空

5.文件结尾检查

6.clearerr()

7.rewind()

8.fgetpos

3.格式化输入输出

格式化输出函数 : 

格式化输入函数:

基于字符的输出

基于字符的输入

基于行的输出

基于行的输入

4.文件存读档

1.freopen()

2.格式化输入输出

3.fstream

5.后文

1.前言

(os:之前技巧1里面提到过用输出输出流进行存档的方法的,但今天来详解一下)

(os:与游戏的关联不大呀!)

∴这一章更多是干货,虽然不好理解(毕竟写文章时zzb的精神状态已经快被搞崩了)

∵zzb是蒟蒻

∴有问题(估计应该会有)尽管提出,zzb会来改正

2.输入/输出概念

c++将输入输出分为三类:

标准I/O 文件I/O 字符串I/O

精确一点:

(1)ifstream类:文件输入流类,支持文件的读操作。

(2)istringstream类:字符串输入流类,支持字符串的输入操作。

(3)ofstream类:文件输出流类,支持文件的写操作。

(4)ostringstream类:字符串输出流类,支持字符串的输出操作。

(5)fstream类:文件输入/输出流类,支持文件的读写操作。

(6)stringstream类:字符串输入/输出流类,支持字符串的输入和输出操作。

3.流的概念

(百度百科)

,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。

(懂了这些,就来讲正文)

4.正文

1.标准I/O流

对象名所属类对应设备含义是否有缓冲
cinistream键盘标准输入yes
coutostream屏幕标准输出yes
cerrostream屏幕标准错误输出no
clogostream屏幕标准错误输出yes

(哦对了,插一句,可以用 fflush(stdin与stdout)清空缓冲 )

 首先很明确,标准输入流,“存在”于

#include<iostream>

当你打开iostream,在翻译一下时:

 再精准一点

所以就去

#include<istream>

里转一转

果然有发现:有一堆右移的重载

 此时,>>操作符(或者说析取)可用于从缓冲区提取数据并存储在变量中。

(而<<操作符(插入器)也一样,有兴趣可以去看一下.

so,我们也可以手写cin

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

int main()
{
    filebuf buf;
    if(buf.open("/proc/self/fd/0",ios::in)==nullptr)
    {
        cout<<"打开文件出错"<<endl;
        return -1;
    }
    istream is(&buf);
    char c=0x00;
    int i=0;
    is>>c>>i;
    cout<<"c="<<c<<endl<<"i="<<i<<endl;
    return 0;
}

而标准输入输出流也有很多东西······

1.get()函数

get()函数用于从输入流中读取单个字符或多个字符,istream类重载了多个get()函数。

 2.getline()函数

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

3.read()函数 

read()函数用于从输入流中读取指定字符个数的字符串。

除此之外,还有:

4.ignore()函数

ignore()函数的作用是跳过输入流中的n个字符

5.gcount()函数

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

6.peek()函数

peek()函数的作用是检测输入流中待读取的字符

7.putback()函数

putback()函数的作用是将上一次读取的字符放回输入流中,使之可被下一次读取(想想你感冒时的鼻子)

 (这肯定要来一个大栗子)

8.istream集合栗子

全是栗子

#include<windows.h>
#include<bits/stdc++.h>
using namespace std;

int ans;
char ch,s[5];

int main()
{
	//get
	printf("请输入一个字符\n");
	ans=cin.get();
	printf("你输入的是: %c\n",char(ans));
    cin.get();
    printf("请输入任意字符(enter结束)\n"); 
    while(1)
	{
        cin.get();
        if(ch!=13) break;
    }
    fflush(stdin);
    //getline
    printf("请输入一个长度<=5的字符串:\n");
    cin.getline(s,5);
    for(int num:s) cout<<num<<" ";
    printf("\n输入一个长度<=5的字符串(以6结束)\n"); 
	cin.getline(s,5,'6');
    for(int num:s) cout<<num<<" ";
    //read
    fflush(stdin);
	fflush(stdout); 
    printf("\n请输入一个字符串(zzb将为你保留前五个):\n");
    cin.read(s,5);
    for(auto num:s) cout<<num;
    //idnore 
    fflush(stdin);
    printf("\n请输入一个长度为8的字符串(zzb将跳过前6个,跳过时遇T停止):\n");
	cin.ignore(6,'T');//跳过前面6个字符,遇到字符'T'终止跳跃
	cin.getline(s,8);//跳跃结束,读取7个字符并存储到s中 
	cout<<s<<endl;
	//gcount
	fflush(stdin);
	printf("请输入一个长度<=20的字符串,zzb将输出你输入的字符个数:\n");
	cin.getline(s,20);//读取字符串并存储到s中
	ans=cin.gcount();//统计上次读取的字符个数
	printf("字符个数(算上回车):%d\n",ans);
	//peek
	fflush(stdin);
	printf("请输入一个字符\n");
    ch=cin.peek();//检测字符
    printf("此时,输入流里%c待输入\n",ch);
    //putback
    fflush(stdin);
	printf("请输入一个字符(zzb将把ta读取后放回输入流再次读取)\n");
	ch=cin.get();
	printf("你输入的是:%c\n",ch); 
	cin.putback(ch);//将字符重新放回输入流
	printf("再读取一遍:%c\n",cin.get());
	printf("\n-----end-----");
    return 0;
}

9.put()函数

put()函数用于输出单个字符。put()函数将字符插入输出流对象,通过输出流对象将字符输出到指定位置。

10.write()函数

write()函数用于输出一个字符串。write()函数将指定个数的字符串插入输出流对象,通过输出流对象将字符串输出到指定位置。

11.ostream集合栗子

(很水了)

#include<windows.h>
#include<bits/stdc++.h>
using namespace std;

int ans;
char ch,s[5];

int main()
{
	cout.put('a');//输出字符'a' 
	cout.put('\n');//输出换行符 
	cout.put('z').put('z').put('b').put('\n');//连续调用
	cout.write("zzb     zzb",4);//输出前3个 
	cout.write("isisisis",2).write(" good.jsafdaosda",6);//连续调用 
    return 0;
}

2.文件I/O流

C++根据文件内容的数据格式分为二进制文件文本文件。采用文件流对象操作文件的一般步骤:

  • 定义一个文件流对象
    • ifstream ifile(只输入用)
    • ofstream ofile(只输出用)
    • fstream iofile(既输入又输出用)
  • 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
  • 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
  • 关闭文件

⚡️ 对于二进制的读写:读写简单,高效快捷,但是缺点是除了字符和字符串,其他的类型从内存中写到文件的时候都是乱码。

文件常见的打开方式 :
(1). in 以读的方式打开文件
(2). out 以写的方式打开文件
(3). binary 以二进制方式对文件进行操作
(4). ate 输出位置从文件的末尾开始
(5). app 以追加的方式对文件进行写入
(6). trunc 先将文件内容清空再打开文件

常用成员函数
(1). put 插入一个字符到文件
(2). write 插入一段字符到文件
(3). get 从文件提取字符
(4). read 从文件提取多个字符
(5). tellg 获取当前字符在文件当中的位置
(6). seekg 设置对文件进行操作的位置
(7). >>运算符重载 将数据以“流”的形式进行输入(用于文本文件)
(8). <<运算符重载 将数据以“流”的形式进行输出(用于文本文件)

 所以呢?

(看似很复杂,但实在不行用cin cout 也不是不行)

so?

流的操作

1.流的关闭

很简单也很水

fclose(FILE *fp);//FILE,文件句柄,后面有写法,当然stdin与stdout也可以

2.缓冲区类型

  1. 全缓冲区
  2. 行缓冲区

具体定义不用过度记

大概知道全缓冲区是填满缓冲区再I/O

行缓冲区是遇' \textbackslash n '再I/O

(缓冲区默认128字节)

3.设置缓冲区属性

#include<cstdio>//头文件是这个 
using namespace std;

int main()
{
	setbuf(FILE *fp,char *buf);//fp前面技巧9讲过,buf是设置的指针,作用:改为全缓/无缓
	setbuffer(FILE *fp,char *buf,size_t size);//同setbuf,但可以更改缓冲区大小
	setlinebuf(FILE *buf);//改成行缓
	setvbuf(FILE *fp,char *buf,int mode,size_t size);//可以制定缓冲(mode)
	/*
	_IOFBF(全缓冲类型)
	_IOLBF(行缓冲类型)
	_IONBF(无缓冲类型 )
	建议在流打开还没操作前转换
	不然可能被虫子(bug)咬死 
	*/ 
    return 0;
}

4.缓冲区清空

前面讲到过

fflush(FILE *fp);

5.文件结尾检查

feof(FILE *fp);

feof函数用来检测是否读到文件的结尾,当没有访问到文件的结尾时,返回为0,当访问到文件的结尾时,返回为1,只有执行读操作时候才对文件结束标志进行操作。

ferror(FILE *fp);

ferror函数用来检测是否出现了读写错误,当访问正常接收时候,函数返回值为0,当访问非正常结束时,返回值为非0,并设置errno的值。此时errno的值为错误发生时由读写函数本身所设定的。

6.clearerr()

clearer(FILE *fp)

7.rewind()

rewind(FILE *stream)

重新指定流的开头

8.fgetpos

fgetpos(FILE *stream)

取得当前文件的句柄

3.格式化输入输出

(==王炸)

格式化输出函数 : 

(1) int printf(const *format,…);
(2) int fprintf(FILE *fp,const char *format,…);//可以直接用fp输入进文件里 
(3) int sprintf(char *str,const char *format,…);
(4) int snprintf(char *str,size_t size,const format,…);
(5) int vprintf(const *format,va_list ap);
(6) int vfprintf(FILE *fp,const char *format, va_list ap);//理论这个也可以,但没有用过 
(7) int vsprintf(char *str,const char *format, va_list ap);
(8) int vsnprintf(char *str,size_t size,const format, va_list ap);

格式化输入函数:

(1) int scanf(const char *format,…);
(2) int fscanf(FILE *fp,const char *format,…);//可以直接从文件里提出来 
(3) int vsscanf(char *str,const char *format,…);
(4) int vscanf(const char *format, va_list ap);
(5) int vfscanf(FILE *fp,const char *format, va_list ap);//同vfprintf 
(6) int vsscanf(char *str,const char *format, va_list ap);

基于字符的输出

(1)int fputc(int c,FILE *fp);//c表示要输出的字符,同样"应该"可以直接输入进文件里 
(2)int putc(int c,FILE *fp);//同上 
(3)int putchar(int c);

基于字符的输入

(4)int fgetc(FILE *fp);//应该可以直接从文件里读入
(5)int getc(FILE *fp);//应该可以直接从文件里读入
(6)int getchar(void);// getc比调用fgetc消耗时间少,但 getc的参数是不能有副作用的表达式,而fgetc可以

基于行的输出

(1) int fputs(const char *str,FILE *fp);//理论上可以直接输出进文件里 
(2) int puts(const char *str);


基于行的输入

(1) char *fgets(char *str,int size, FILE *fp);//理论上可以直接从文件里读入 
(2) char *gets(char *str);

流的操作讲完后

文件存读档也给一下吧······

4.文件存读档

1.freopen()

OIer的心头之恨呀!

写法·····简单快捷:

#include<bits/stdc++.h>
using namespace std;

int main()
{
	freopen("输入文件名.类型","操作方式",stdin);
	freopen("输出文件名.类型","操作方式",stdout);//未找到会自动新建呢 @杨某一辰 
	/*
	操作 
	*/
    return 0;
}

(os:操作方式多种多样,给一下:)

type文件类型是否新建是否清空可读可写读写位置
r文本文件NONOYESNO文件开头
r+文本文件NONOYESYES文件开头
w文本文件YESYESNOYES文件开头
w+文本文件YESYESYESYES文件开头
a文本文件NONONOYES文件结尾
a+文本文件YESNOYESYES文件结尾
rb二进制文件NONOYESNO文件开头
r+b或rb+二进制文件NONOYESYES文件开头
wb二进制文件YESYESNOYES文件开头
w+b或wb+二进制文件YESYESYESYES文件开头
ab二进制文件NONONOYES文件结尾
a+b或ab+二进制文件YESNOYESYES文件结尾

(同为颓废人,建议类型用txt,操作方式不要太离谱(比如a))

2.格式化输入输出

有很多(但不知道都能不能用)

int fprintf(FILE *fp,const char *format,…);
int vfprintf(FILE *fp,const char *format, va_list ap);
int fscanf(FILE *fp,const char *format,…);
int vfscanf(FILE *fp,const char *format, va_list ap);
int fputc(int c,FILE *fp);
int putc(int c,FILE *fp); 
int fgetc(FILE *fp);
int getc(FILE *fp);

(等等,不会有人不会搞fp吧······)

fp写法:

FILE* fp=fopen("名字.类型","操作方式");

所以统一叫做fopen写法吧······

给个栗子

void cd(void)
{
    FILE* fp = fopen("名字.txt","wb");
    fprintf(fp,"%d",变量名);
    fclose(fp);
}

void dd(void)
{
	FILE* fp = fopen("名字.txt","rb");
    if(fp != NULL)
	{
        fscanf(fp,"%d",&变量名);
        fclose(fp);
    }
	else
	{
        cd();
		printf("未找到存档,已新建");//@杨某一辰 
        return;
    }
}

3.fstream

仍然是4件套:

创建流,打开文件,读写,关闭流

#include<bits/stdc++.h>
using namespace std;

int main()
{
	ifstream  fin;//创建流 
	ofstream fout;
	
	//打开流
	/*
	ios::in 读文件
	ios::out 写文件,直接用会丢弃已有数据,即隐含为trunc
	ios::binary 二进制方式
	ios:app 追加写,要配合out使用,直接写会隐含用ios::out
	ios::trunc 覆盖写,要配合out使用
	ios::out|ios::binary 二进制写
	*/
	
//	fin.open("路径/名字.类型",ios::app|ios::out);//这样配合
//	如 
	fout.open("D:/z_z_b.txt",ios::out);
	fin.open("D:/z_z_b.txt",ios::in);
	//写数据
	fout<<"zzb好帅!"<<endl;
	//读数据 
	
	//判断 
	if(!fin.is_open()) std::cerr<<"cannot open the file";
	//或者
	if(!fin) std::cerr<<"cannot open the file";
	else
	{
		string k;
		fin>>k;
		//当然,也可以换变量类型
		//同时,fin.getline(s,sizeof(s))  c=fin.get() 都可以 
		cout<<k<<endl;
	}
	
	fout.close();
	fin.close();
	return 0;
}

5.后文

那么这一篇基本就完了

(写了这么多,能不能给个赞呢?)

上一篇:c++游戏小技巧11:goto_L('ω')┘脏脏包└('ω')」的博客-CSDN博客

下一篇:未完待续······

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值