目录
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.后文
(os:之前技巧1里面提到过用输出输出流进行存档的方法的,但今天来详解一下)
(os:与游戏的关联不大呀!)
∴这一章更多是干货,虽然不好理解(毕竟写文章时zzb的精神状态已经快被搞崩了)
∵zzb是蒟蒻
∴有问题(估计应该会有)尽管提出,zzb会来改正
c++将输入输出分为三类:
标准I/O 文件I/O 字符串I/O
精确一点:
(1)ifstream类:文件输入流类,支持文件的读操作。
(2)istringstream类:字符串输入流类,支持字符串的输入操作。
(3)ofstream类:文件输出流类,支持文件的写操作。
(4)ostringstream类:字符串输出流类,支持字符串的输出操作。
(5)fstream类:文件输入/输出流类,支持文件的读写操作。
(6)stringstream类:字符串输入/输出流类,支持字符串的输入和输出操作。
(百度百科)
流,简单来说就是建立在面向对象基础上的一种抽象的处理数据的工具。在流中,定义了一些处理数据的基本操作,如读取数据,写入数据等,程序员是对流进行所有操作的,而不用关心流的另一头数据的真正流向。流不但可以处理文件,还可以处理动态内存、网络数据等多种数据形式。
(懂了这些,就来讲正文)
对象名 | 所属类 | 对应设备 | 含义 | 是否有缓冲 |
---|---|---|---|---|
cin | istream | 键盘 | 标准输入 | yes |
cout | ostream | 屏幕 | 标准输出 | yes |
cerr | ostream | 屏幕 | 标准错误输出 | no |
clog | ostream | 屏幕 | 标准错误输出 | yes |
(哦对了,插一句,可以用 fflush(stdin与stdout)清空缓冲 )
首先很明确,标准输入流,“存在”于
#include
当你打开iostream,在翻译一下时:
所以就去
#include
里转一转
果然有发现:有一堆右移的重载
此时,操作符(或者说析取器)可用于从缓冲区提取数据并存储在变量中。
(而<<操作符(插入器)也一样,有兴趣可以去看一下.
so,我们也可以手写cin
#include
#include
using namespace std;
int main()
{
filebuf buf;
if(buf.open("/proc/self/fd/0",ios::in)==nullptr)
{
cout<<"打开文件出错"<>c>>i;
cout<<"c="<
而标准输入输出流也有很多东西······
get()函数用于从输入流中读取单个字符或多个字符,istream类重载了多个get()函数。
getline()函数用于从输入流中读取字符,直到读取到指定长度的字符或遇到终止字符时结束读取。getline()有两种重载形式。
read()函数用于从输入流中读取指定字符个数的字符串。
除此之外,还有:
ignore()函数的作用是跳过输入流中的n个字符
gcount()函数的作用是计算上一次读取到的字符个数
peek()函数的作用是检测输入流中待读取的字符
putback()函数的作用是将上一次读取的字符放回输入流中,使之可被下一次读取(想想你感冒时的鼻子)
(这肯定要来一个大栗子)
全是栗子
#include
#include
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<
put()函数用于输出单个字符。put()函数将字符插入输出流对象,通过输出流对象将字符输出到指定位置。
write()函数用于输出一个字符串。write()函数将指定个数的字符串插入输出流对象,通过输出流对象将字符串输出到指定位置。
(很水了)
#include
#include
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;
}
C++根据文件内容的数据格式分为二进制文件和文本文件。采用文件流对象操作文件的一般步骤:
⚡️ 对于二进制的读写:读写简单,高效快捷,但是缺点是除了字符和字符串,其他的类型从内存中写到文件的时候都是乱码。
文件常见的打开方式 :
(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?
流的操作
很简单也很水
fclose(FILE *fp);//FILE,文件句柄,后面有写法,当然stdin与stdout也可以
具体定义不用过度记
大概知道全缓冲区是填满缓冲区再I/O
行缓冲区是遇再I/O
(缓冲区默认128字节)
#include//头文件是这个
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;
}
前面讲到过
fflush(FILE *fp);
feof(FILE *fp);
feof函数用来检测是否读到文件的结尾,当没有访问到文件的结尾时,返回为0,当访问到文件的结尾时,返回为1,只有执行读操作时候才对文件结束标志进行操作。
ferror(FILE *fp);
ferror函数用来检测是否出现了读写错误,当访问正常接收时候,函数返回值为0,当访问非正常结束时,返回值为非0,并设置errno的值。此时errno的值为错误发生时由读写函数本身所设定的。
clearer(FILE *fp)
rewind(FILE *stream)
重新指定流的开头
fgetpos(FILE *stream)
取得当前文件的句柄
(==王炸)
(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);
流的操作讲完后
文件存读档也给一下吧······
OIer的心头之恨呀!
写法·····简单快捷:
#include
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))
有很多(但不知道都能不能用)
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;
}
}
仍然是4件套:
创建流,打开文件,读写,关闭流
#include
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好帅!"<>k;
//当然,也可以换变量类型
//同时,fin.getline(s,sizeof(s)) c=fin.get() 都可以
cout<
那么这一篇基本就完了
(写了这么多,能不能骗给个赞呢?)
上一篇:c++游戏小技巧11:goto_L('ω')┘脏脏包└('ω')」的博客-CSDN博客
下一篇:未完待续······