目录
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流
对象名 | 所属类 | 对应设备 | 含义 | 是否有缓冲 |
---|---|---|---|---|
cin | istream | 键盘 | 标准输入 | yes |
cout | ostream | 屏幕 | 标准输出 | yes |
cerr | ostream | 屏幕 | 标准错误输出 | no |
clog | ostream | 屏幕 | 标准错误输出 | 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.缓冲区类型
- 全缓冲区
- 行缓冲区
具体定义不用过度记
大概知道全缓冲区是填满缓冲区再I/O
行缓冲区是遇再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 | 文本文件 | NO | NO | YES | NO | 文件开头 |
r+ | 文本文件 | NO | NO | YES | YES | 文件开头 |
w | 文本文件 | YES | YES | NO | YES | 文件开头 |
w+ | 文本文件 | YES | YES | YES | YES | 文件开头 |
a | 文本文件 | NO | NO | NO | YES | 文件结尾 |
a+ | 文本文件 | YES | NO | YES | YES | 文件结尾 |
rb | 二进制文件 | NO | NO | YES | NO | 文件开头 |
r+b或rb+ | 二进制文件 | NO | NO | YES | YES | 文件开头 |
wb | 二进制文件 | YES | YES | NO | YES | 文件开头 |
w+b或wb+ | 二进制文件 | YES | YES | YES | YES | 文件开头 |
ab | 二进制文件 | NO | NO | NO | YES | 文件结尾 |
a+b或ab+ | 二进制文件 | YES | NO | YES | YES | 文件结尾 |
(同为颓废人,建议类型用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博客文章来源:https://www.toymoban.com/news/detail-647711.html
下一篇:未完待续······文章来源地址https://www.toymoban.com/news/detail-647711.html
到了这里,关于c++游戏小技巧12:输入输出流(存读档超全版)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!