一、引言
本文将对c语言的标准IO的输入输出函数和c++标准库的输入输出流进行详细汇总,如果什么有缺漏和错误,欢迎各位网友指出,我会立马更新~
二、c语言标准IO库
1、fgetc、getc、getchar
作用:从文件中获取一个字符
头文件:#include <stdio.h>
原型: int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void); //专门用于stdin
参数:stream:文件指针
返回值:成功:读取到的字符 失败:EOF(-1)
备注:当返回EOF时,文件可能是已到达末尾,或者出错。另外,上面的函数,如果输入的是标准输入流stdin(键盘的输入),那么它们会阻塞程序,等待用户完成键盘输入;如果是普通文件,它们是不会阻塞的。
2、fputc、putc、putchar
作用:将一个字符输入到文件中
头文件:#include <stdio.h>
原型: int fputc(int c,FILE *stream);
int putc(int c,FILE *stream);
int putchar(int c); //专门用于stdout
参数:c:要输入的字符 stream:文件指针
返回值:成功:输入的字符指针 失败:EOF
备注:fgetc和fputc、getc和putc、getchar和putchar一般成对使用。
示例代码:
#include <stdio.h>
int main(){
FILE* fp;
char x;
fp = fopen("./hello.txt","r+");
if(fp == NULL){
perror("打开文件失败\n");
return -1;
}
while(1){
x = fgetc(fp);
if(x == EOF){
//由于返回EOF的结果可能是到文件末尾,可能是出错,那么怎么区别呢?
if(feof(fp)){ //feof判断末尾
putchar('\n'); //输出完毕后换行
break;
}
else
return -1;
}
putchar(x);
}
fclose(fp);
return 0;
}
3、fgets、gets
作用:从制定文件中读取最多一行数据
头文件:#include <sys/ioctl.h>
原型: char* fgets(char* s,int size,FILE* stream);
char* gets(char* s); //默认从stdin读
参数:s:自定义缓冲区指针 size:缓冲区大小
stream:要读取数据的文件指针
返回值:成功:自定义缓冲区指针s 失败:NULL
备注:由于gets没有指定缓冲区的大小,所以容易造成缓冲区溢出,接口过时。在fgets中,实际上最多读取的字符数是size-1,因为缓冲区的末尾需要一个’\0’占位。
4、fputs、puts
作用:将字符串输出到文件中
头文件:#include <sys/ioctl.h>
原型:int fputs(const char* s, FILE* stream);
int puts(const char* s); //默认输出到stdout
参数:s:自定义缓冲区 stream:即将被写入数据的文件指针
返回值:成功:非负整数 失败:EOF
示例代码:
#include <stdio.h>
#include <sys/ioctl.h>
int main(){
FILE* fp;
FILE* result;
char buf1[20];
fp = fopen("./hello.txt","r+");
result = fopen("./result.txt","r+");
if(fp == NULL || result == NULL){
return -1;
}
fgets(buf1,sizeof(buf1),fp);
fputs(buf1,result);
fclose(fp);
fclose(result);
return 0;
}
5、fread
作用:从指定文件读取若干个数据块
头文件:#include <sys/ioctl.h>
原型:size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
参数:ptr:自定义缓冲区指针大小 size:数据块大小
nmenb:数据块个数 stream:被读取数据的文件指针
返回值:成功:读取的数据块个数,等于nmenb
失败:小于nmemb,或等于0
备注:当数据块不是刚好读完时,返回的值是向下取整的,比如:要读取大小是100字节,块数是5的空间,但实际大小是499个字节,那么返回值是4,因为最后一块没有满,此时如果和fwrite()搭配使用的时候,要特别注意,需要额外处理。
6、fwrite
作用:将若干数据块写入文件
头文件:#include <sys/ioctl.h>
原型:size_t fwrite(const void* ptr, size_t size, size_t nmemb,
FILE* stream)
参数:ptr:缓冲区指针 size:块的大小
nmemb:块的数量 stream:写入的文件
返回值:成功:写入的数据块个数,等于nmemb
失败:小于nmemb,或等于0
备注:size和nmemb要合理设计,以防止写入额外的无用数据
示例代码:
#include <sys/ioctl.h>
#include <stdio.h>
#define SIZE 512
#define NUM 2
/*
代码实现文件拷贝的功能
*/
int main(){
FILE* fp_source;
FILE* fp_to;
char buf[SIZE*NUM];
int pre_pos,last_pos;
fp_source = fopen("./hello.txt","r+");
fp_to = fopen("./result.txt","r+");
if(fp_source==NULL || fp_to==NULL){
return -1;
}
while(1){
pre_post = ftell(fp_source); //获取文件的位置偏移量
if(fread(buf,SIZE,NUM,fp_source) < NUM){
//末尾未满块的处理
if(feof(fp_source)){
last_pos = ftell(fp_source);
fwrite(buf,pre_pos-last_pos,1,fp_to);
break;
}
else{
return -1;
}
}
fwrite(buf,SIZE,NUM,fp_to);
}
fclose(fp_source);
fclose(fp_to);
return 0;
}
7、fprintf、printf、snprintf、sprintf
作用:将格式化的数据写入指定的文件或者内存
头文件:#include <stdio.h>
原型:int fprintf(FILE* restrict stream, const char* restrict format,…)
int printf(const char* restrict format, …)
int snprintf(char* restrict s, size_t n, const char* restrict format, …)
int sprintf(char* restrict s,size_t n, const char* restrict format,…)
参数:stream:写入数据的文件指针 format:格式控制串
s:写入数据的自定义缓冲区 n:自定义的缓冲区大小
返回值:成功:成功写入的字节数 失败:-1
备注:由于sprintf没有指定缓冲区的大小,所以有溢出的风险,相比之下,snprintf更好。
示例:
#include <stdio.h>
int main(){
char buf[30];
int a = 10;
char b = 90;
char temp[20]="hello world";
snprintf(buf,30,"%d + %d = %s",a,b,temp);
puts(buf);
return 0;
}
8、fscanf、scanf、sscanf
作用:从指定的文件或者内存中读取格式化的数据
头文件:#include <stdio.h>
原型:int fscanf(FILE* restrict stream, const char* restrict format,…)
int scanf(const char* restrict format,…)
int sscanf(const char* restrict s,const char* restrict format, …)
参数:stream:读出数据的文件指针 format:格式控制串
s:读出数据的自定义缓冲区
返回值:成功:正确匹配且赋值的数据个数
失败:EOF
备注:fscanf函数有些难点是对“分隔符”的识别和在换行时对“换行符”的处理,经过本人多次验证,发现如果你使用“空格”作分隔符,那么该函数会自动处理换行符,但是如果使用其它分隔符,会出现bug,所以本人建议最好使用空格作换行符,而且允许数据之间的空格出现多次,该函数会当成一个空格处理。
示例:
#include <stdio.h>
int main() {
FILE *file = fopen("hello.txt", "r");
if (file == NULL) {
return -1;
}
char name[20];
char sex;
int age;
float height;
//使用空格作为换行符
while (fscanf(file, "%s %c %d %f", name,&sex,&age,&height) != EOF) {
// 处理读取到的数据
printf("%s %c %d %.1f\n", name,sex,age,height);
}
fclose(file);
return 0;
}
三、c++标准IO库
在c++中,由于引入了流对象,所以IO库的使用主要是cin、cout的成员函数的使用。有关输入输出流的具体介绍,可以看我另一篇文章,本文知汇总一些常用的成员函数。
1、get
作用:在输入流中获取单个字符或字符串
头文件:#include <iostream>
原型:int get();
istream& get(char& var);
istream& get ( char* s, streamsize n );
istream& get ( char* s, streamsize n, char delim );
参数:var:存放字符的变量 s:存放字符串的缓冲区指针
n:允许读入字节个数 delim:自定义结束符
返回值:第一个函数:
成功:获取的字符 失败:EOF
其余函数:
成功:输入流对象,一般是cin(为了支持链式输入操作)
失败:失败式的流对象,可以用cin.fail()检测
备注:前两个是单个字符的获取,分隔符按普通字符处理;后两个是字符串的读取,遇到换行符(默认)或者自定义结束符时,结束读取,但是换行符或自定义结束符会残留在缓冲区,注意下次使用时的缓冲区清除的细节。
示例:
#include <iostream>
#include <fstream>
using namespace std;
int main(){
char a;
char b;
fstream fp;
fp.open("./hello.txt",ios_base::in|ios_base::out); //打开文件,可读可写
a = cin.get(); //从标准输入流中获取单个字符
b = fp.get(); //从文件流中获取单个字符
cout<<a<<" "<<b<<endl;
char arr1[20];
char arr2[20];
cin.get(arr1,20); //从标准输入流中获取字符串,遇到换行符或满20个字符结束
fp.get(arr2,20);//从文件流中获取字符串,遇到换行符或满20个字符结束
cout<<arr1<<endl<<arr2<<endl;
cin.get(arr1,20,' ');//从标准输入流中获取字符串,遇到空格或满20个字符结束
fp.get(arr2,20,' ');//从文件流中获取字符串,遇到空格或满20个字符结束
cout<<arr1<<endl<<arr2<<endl;
fp.close();
return 0;
}
2、getline(成员函数)
作用:在输入流中获取一行字符串
头文件:#include <iostream>
原型:istream& getline(char* s, streamsize count);
istream& getline(char* s, streamsize count, char delim);
参数:s:缓冲区指针 count:允许读入字节个数
delim:自定义结束符
返回值:成功:输入流对象,一般是cin(为了支持链式输入操作)
失败:失败式的流对象,可以用cin.fail()检测
备注:getline和get的后两个相似,不同是:cin.getline不会将结束符或者换行符残留在输入缓冲区中,所以当按行读取字符串时,建议使用getline函数。
示例:
#include <iostream>
using namespace std;
int main(){
char arr[20];
cin.getline(arr,20);
cout<<arr<<endl;
return 0;
}
3、getline(普通函数)
作用:在输入流中获取一行字符串
头文件:#include <string>
原型:istream& getline ( istream& is, string& str);
istream& getline ( istream& is, string& str, char delim);
参数:is:输入流对象,比如cin str:自定义缓冲区
delim:自定义结束符
返回值:成功:输入流对象,一般是cin(为了支持链式输入操作)
失败:失败式的流对象,可以用cin.fail()检测
备注,getline的成员函数和普通函数的作用完全一样,只是用法不同,还有使用的字符串缓冲区不同,前者是char*,后者是string
示例:
#include <string>
#include <iostream>
using namespace std;
int main()
{
string str;
getline(cin,str);
cout<<str<<endl;
return 0;
}
4、其余接口
由于c++有关输入输出流的接口太多,难以一一列举,但是我们要掌握其核心,就是为流对象服务的,要想实现某种功能,只需要查看相应流类给出的成员函数有哪些。
下面给出一个很方便查找相关成员函数的网址:std::basic_fstream - cppreference.com
都读到这里了,还不给个赞?你的点赞支持,是我持续写作的动力~
格式控制符表格
格式控制符 | 含义 |
%d | 有符号十进制整型数 |
%u | 无符号十进制整型数 |
%o | 无符号八进制整型数 |
%x | 无符号十六进制整型数 |
%c | 字符 |
%s | 字符串 |
%f | 计数法单精度浮点数 |
%e | 科学计数法单精度浮点数 |
%p | 指针 |
%.5s | 取字符串前5个 |
%.5f | 保留小数点后五位 |
%5d | 位宽最少5个字符,右对齐 |
%-5d | 位宽最少5个字符,左对齐 |
%hd | 半个有符号数十进制整型数 |
%hhd | 半半个有符号数十进制整型数 |
%lf %le | 双精度浮点数 |
%Lf %Le | 长双精度浮点数 |