I是输入,O是输出
都是以文件的形式,以字符流形式输入,以像素点形式输出。
I/O流的打开 //打开文件
#include
FILE* fopen { //其实是一个被typdef修改的结构体
const char * path, //文件路径,且不可更改
const char * mode //打开模式,且不可更改
};
成功返回I/O流指针,作为后续I/O流函数的参数,失败返回NULL。
打开模式:
r - 只读,文件必须存在,从头开始读
w -只写,文件不存在就创建,存在就清空,从头开始写
a -追加,文件不存在就创建,存在不请空,从尾开始写
r+ -读写,文件必须存在,从头开始读写
w+ -写读,文件不存在就创建,存在就清空,从头开始写读
a+ -追读,文件不存在就创建,存在不清空,从头开始读,从尾开始写
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。
上述的形态字符串都可以再加一个b字符,如rb、w+b或ab+等组合,加入b 字符用来告诉函数库打开的文件为二进制文件,而非纯文字文件。不过在POSIX系统,包含Linux都会忽略该字符。由fopen()所建立的新文件会具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)权限,此文件权限也会参考umask值。
原文链接:https://blog.csdn.net/Zhangjay/article/details/6531551
I/O流的关闭
int fclose{
FILE *fp //I/O流指针
;}
成功返回0,失败返回EOF
打开文件示例如下:
//文件操作的标准C库函数
#include <stdio.h>
int main(void) {
FILE *fp = NULL;
//打开文件
//fp = fopen("a.txt", "r"); //以只读方式打开当前目录下的a.txt文件
fp = fopen("a.txt", "w"); //以只写方式打开当前目录下的a.txt文件,存在则清空,不存在则创建
if(fp == NULL) {
printf("打开失败.\n");
return -1;
}
printf("打开成功\n"); //以后访问fp就是在访问文件本身
//关闭文件
fclose(fp);
fp = NULL; //好习惯
return 0;
}
格式化I/O
格式化输出 //向文件中保存数据
int fprintf {
FILE* stream, // I/O流指针
const char* format, //格式字符串 整型格式
………… // 输出数据
};
fprintf(fp,"%d",520); //fp是上文中的文件指针,输入%d格式的整型数进入fp文件中
fprintf(fp,"%d %d",520,521); //fp是上文中的文件指针,输入%d格式的整型数进入fp文件中
成功返回输出字符串,失败返回负数
从文件中提取数据
int fscanf {
FILE* stream;
const char* format
…………
};
fscanf(fp, "%d", &a) //从文件里按照%d的格式拿到数据给变量a
成功返回实际输入的数据项数,失败或遇到文件尾返回EOF
其主要知识点看代码:
//文件操作的标准C库函数
//当运行程序时,操作系统会帮助咱们的程序默认打开三个文件,这三个文件分别代表:键盘(又称标准输入),显示器(又称标准输出),显示器(又称标准出错),同样fopen打开也会得到三个FILE*指针,分别叫
//stdin,stdout,stderr,也就是:FILE *stdin, *stdout, *stderr
//stdin:代表标准输入,就是键盘
//stdout:代表标准输出,就是显示器
//stderr:代表标准出错,就是显示器
#include <stdio.h>
int main(void) {
FILE *fp = NULL;
//打开文件
fp = fopen("a.txt", "r"); //以只读方式打开当前目录下的a.txt文件
if(fp == NULL) {
printf("打开失败.\n");
return -1;
}
printf("打开成功\n"); //以后访问fp就是在访问文件本身
int i = 0;
char str[20] = {0};
double d = 0;
//按照指定的格式从文件a.txt中获取数据保存到变量i,str,d中
fscanf(fp, "%d%s%lf", &i, str, &d);
printf("i = %d, str = %s, d = %lg\n", i, str, d);
//关闭文件
fclose(fp);
fp = NULL; //好习惯
FILE *fpw = fopen("b.txt", "w+");
//将变量i,str,d中的数据按照指定的格式保存到文件b.txt中
fprintf(fpw, "copy:%d,%s,%lg\n", i, str, d);
fclose(fpw);
//stdin,stdout,stderr三个默认的文件指针演示
fscanf(stdin, "%d%s%lf", &i, str, &d);//从键盘上按照指定的格式输入数据保存到变量i,str,d
printf("i = %d, str = %s, d = %lf\n", i, str, d);
fprintf(stdout, "i = %d, str = %s, d = %lf\n", i, str, d);//打印变量i,str,d到显示器
fprintf(stderr, "i = %d, str = %s, d = %lf\n", i, str, d);//打印变量i,str,d到显示器
return 0;
}
注意: fscanf("%d%s%lf") 中间不要加空格!!
//stdout:代表标准输出,就是显示器
//stderr:代表标准出错,就是显示器
二者的区别是一个自带缓冲区,一个不带缓冲区,stderr不带缓冲区即输入直接输出,不做缓存
输出字符
int fputc { //向文件里保存一个字符
int c;
FILE* stream
};
成功返回实际输出的字符,失败返回EOF
int fgetc { //从文件读取一个字符
FILE* stream
};
成功返回实际输入的字符,失败或遇到文件尾返回EOF 类似NULL
使用这两个文件做拷贝
//fputc和fgetc标准库函数演示
#include <stdio.h>
int main(void) {
FILE *fpr = fopen("a.txt", "r");
FILE *fpw = fopen("b.txt", "w+");
int ch; //暂存从文件中读取的字符
while(1) {
ch = fgetc(fpr); //从文件a.txt中读取一个字符保存到ch中
if(ch == EOF) //判断是否读取失败或者读取到了文件尾部
break;
fputc(ch, fpw); //将读取到的字符保存到文件b.txt中
}
fclose(fpr);
fclose(fpw);
return 0;
}
非格式化I/O
输出字符串:
int fputs{ 向文件里保存一个字符串
const char *s, //字符串首地址
FILE* stream // I/O流指针
};
fputs("hello", fp)
成功返回非负数,失败返回EOF,不追加换行符
char* fgets{ 从文件里取一个字符串
char* s; //字符串缓冲区首地址
int size, //字符串缓冲区大小
FILE* stream
};
fgets(str, 10, fp)
最多读取size -1 个字符,追加结尾空字符读到换行符返回,不把换行符换成空字符。成功返回s,失败或者遇到文件尾返回NULL
字符串文件拷贝示例如下:
//fputs和fgets标准库函数演示
#include <stdio.h>
int main(void) {
FILE *fpr = fopen("a.txt", "r");
FILE *fpw = fopen("b.txt", "w+");
char str[4] = {0}; //暂存读取到的字符串数据
while(fgets(str, 4, fpr) != NULL) //循环从文件a.txt读取字符串保存到str中,一次读3个字符
fputs(str, fpw); //将数组中的字符串数据保存到文件b.txt中
fclose(fpr);
fclose(fpw);
return 0;
}
最重要的三个I/O结构体:
二进制I/O
1.二进制输出:(写入)
size_t fwrite { //向文件写入数据
const void* ptr, //缓冲区地址 你要写入的数据对应的内存首地址
size_t size, //元素字节数 写入的单个数据的大小
size_t nmemb, //期望输出元素数
FILE* stream; //I/O流指针
};
返回实际写入元素个数,遇到错误,返回值比nmemb小或为0. 写入的数据是二进制的。
可以在命令界面利用 hexdump a.txt 把文件内容按照16进制的格式显示出来。
2.二进制输入 (读取)
size_t fread { //从一个文件中读取数据
void* ptr, //缓冲区地址,暂存从文件中读取的数据
size_t size, //元素字节数
size_t nmemb, //期望读取元素数
FILE* stream //I/O流指针
};
成功返回实际读取到的元素个数,遇到错误或文件尾,返回值比nmemb小或为0
rewind(fp); //将文件的读写位置重新指定到文件的最开头
解释读写位置:
typedef struct file{
char *filename;
int mode;
unsigned long offset; //偏移量:用来记录文件的读写位置
}
结构体中的参数,用于记录读写位置
文件位置与随机访问:
设置文件读写位置
int fseek {
FILE* stream, // I/O流指针
long offset, //偏移字节数
int whence //偏移起点
//SEEK_SET: 从文件头
// SEEK_CUR: 从当前位置
// SEEK_END: 从文件尾
};
成功返回0,失败返回-1
void rewind (FILE* stream); // fseek(stream,0l,SEEK_SET) rewind函数其实就相当于fseek函数,第二个0是从文件头,偏移是0,l 是因为offset默认是long类型,加 l 增加代码可读性
获取文件位置
long ftell {
FILE * stream // I/O流指针
};
成功返回当前文件位置,失败返回-1
是否到文件尾
int feof (FILE* stream); //返回0是没有读到文件尾,返回非0是文件尾
是否出现错误
int ferror(FILE* stream); //返回非0,文件错误,返回0,则不是文件出错导致EOF
这是为了区分文件是读取失败还是到文件尾
if(feof(fp)){
printf("读到末尾了.\n");
return 0;
}
if(ferror(fp)){
printf("读失败了.\n");
return -1;
}
//fwrite,fread,fseek,rewind,ftell函数演示
#include <stdio.h>
int main(void) {
FILE *fp = fopen("a.txt", "w+");
int a[] = {1,2,3,4,5,6,7,8};
int len = sizeof(a)/sizeof(a[0]);
int size = 0;
size = fwrite(a, sizeof(a[0]), len, fp);//向a.txt文件写入8个数据,单个数据大小4字节
printf("实际写入了%d个数据.\n", size);
//将文件的读写位置重新指定到文件的最开头
rewind(fp); //如果不加这个函数,则会在上个写入数据的末尾继续向后读,则读取数据为0
int b[8] = {0}; //暂存从文件中读取的数据
size = fread(b, sizeof(int), 10, fp);//从a.txt文件中读取10个数据,单个数据大小4字节
printf("实际读取了%d个数据.\n", size);
for(int i = 0; i < size; i++)
printf("%d ", b[i]);
printf("\n");
//fseek函数
int c[2] = {0}; //暂存读取到的数据
fseek(fp, 8, SEEK_SET);//从文件开头往后8个字节开始操作文件(读写位置位于3)
//1 2 3 4 5 6 7 8
// ^
fread(c, sizeof(int), 2, fp);//读取完毕之后,文件读写位置跑到5这个位置
//1 2 3 4 5 6 7 8
// ^
printf("%d %d\n", c[0], c[1]);
fseek(fp, 8, SEEK_CUR);//从当前位置(5)往后8个字节开始操作文件(读写位置位于7)
//1 2 3 4 5 6 7 8
// ^
fread(c, sizeof(int), 2, fp);//读取完毕之后,文件读写位置跑到末尾
//1 2 3 4 5 6 7 8
// ^
printf("%d %d\n", c[0], c[1]);
fseek(fp, -12, SEEK_END);//从文件的末尾往前12个字节开始操作文件(读写位置位于6)
//1 2 3 4 5 6 7 8
// ^
fread(c, sizeof(int), 2, fp);//读取完毕之后,文件读写位置跑到8
//1 2 3 4 5 6 7 8
// ^
printf("%d %d\n", c[0], c[1]);
printf("当前文件的读写位置是:%ld\n", ftell(fp));
fclose(fp);
return 0;
}