目录
IO:输入输出
操作对象:文件
Linux系统一切皆是文件:
文件分类:
1.block b 块设备文件 按块扫描设备信息的文件
2.char c 字符设备文件 按字符扫描设备信息的文件
3.directory d 目录文件 保存或管理文件
4. - 普通文件 保存数据信息的文件(代码、图片、音视频、压缩包等)
5.link l 链接文件 指向其他文件的文件(类似与window系统的快捷方式)
6.socket s 套接字文件 用于进程间通信
7.pipe p 管道文件 用于进程间通信
1.标准IO
stdio.h
主要操作普通文件
1.打开文件
2.读写文件
3.关闭文件
2.特殊的流
默认打开的流
stdin 标准输入流 行缓存
stdout 标准输出流 行缓存
stderr 标准错误流 不缓存
gets、getchar、scanf是基于stdin实现的
puts、putchar、printf是基于stdout实现的
perror是基于stderr
3.缓存:
1.全缓存
4096 (4k)
缓存区满刷新
与文件建立的缓存一般为全缓存
刷新条件:
1.缓存区存满了刷新
2.fflush函数接口刷新
3.关闭流时会刷新(fclose)
2.行缓存
1024 (1k)
遇到\n刷新
与终端建立的缓存都是行缓存
刷新条件:
1.缓存区满刷新
2.遇到\n刷新
3.fflush函数刷新
4.关闭流时会刷新
3.不缓存
0 0k
立即刷新
刷新条件:
1.立即刷新
1.对设备的操作不允许缓存
2.通信不允许缓存
3.出错处理不缓存
4.函数接口
1.fopen
FILE *fopen(const char *pathname, const char *mode);
功能:
打开pathname对应的文件并建立一个文件流
参数:
pathname:文件路径
mode:打开方式
r 只读 如果文件存在则只读打开
如果文件不存在报错
r+ 读写 如果文件存在则读写打开
如果文件不存在报错
w 只写 如果文件存在则清0,只写打开
如果文件不存在则创建
w+ 写读 如果文件存在则清0,读写打开
如果文件不存在则创建
a 追加只写 如果文件存在则追加只写打开
如果文件不存在则创建
a+ 追加读写 如果文件存在则追加读写打开
如果文件不存在则创建
返回值:
成功返回FILE*的指针(所以要定义一个FILE类型的指针去接收返回的指针)
失败返回NULL并且将错误码置位
#include <stdio.h> int main(void) { FILE *fp = NULL; fp = fopen("a.txt", "r"); //定义一个指针去接受返回的指针 if (NULL == fp) { perror("打开 a.txt 文件失败"); //perror会显示打开失败的原因 return -1; } //判断是否打开失败 return 0; }
2.fclose
int fclose(FILE *stream);
功能:
关闭流
参数:
stream:文件流
返回值:
成功返回0
失败返回EOF(-1)
3.setvbuf
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
功能:
改变流的缓存类型
参数:
stream:文件流
buf:缓存区的首地址
mode:
_IOFBF 全缓存
_IOLBF 行缓存
_IONBF 不缓存
size:缓存区大小
返回值:
成功返回0
失败返回非0
#include <stdio.h> int main(void) { char tmpbuff[4096] = {0}; //全缓存内存为4K,所以定义一个4k大小的缓存区。 #if 0 setvbuf(stdout, tmpbuff, _IOFBF, 4096); printf("stdout被切换为全缓存\n"); //改变为全缓存,这时候运行不会打印 setvbuf(stdout, NULL, _IONBF, 0); printf("stdout被切换为不缓存\n"); //改变为不缓存,这时候运行有\n的会被打印,没有的不会打印 #endif setvbuf(stdout, tmpbuff, _IOLBF, 1024); //改编为行缓存 printf("hello world!\n"); while (1) { } //while循环是为了不让代码结束这样才能看到全缓存的效果 return 0; }
4.fputc
int fputc(int c, FILE *stream);
功能:
向流中写入一个字符
参数:
c:写入的字符
stream:文件流指针
返回值:
成功返回写入字符的ASCII码值
失败返回EOF(-1)
#include <stdio.h> int main(void) { FILE *fp = NULL; char ch = 'A'; /* 打开文件 */ fp = fopen("a.txt", "w");//接收文件的地址 if (NULL == fp) { perror("fopen a.txt failed"); return -1; } /* 读写文件 */ fputc('a', fp); fputc(ch, fp); fputc(ch+32, fp); /* 关闭文件 */ fclose(fp); return 0; }
练习:
1.编写程序利用fputc将"hello world"写入到file.txt文件中
#include <stdio.h> int main(void) { FILE *fp = NULL; char str[32] = {"hello world"}; char *p = str; fp = fopen("file.txt", "w"); if (NULL == fp) { perror("fail to fopen"); return -1; } while (*p != '\0') { fputc(*p, fp); p++; }//用循环将所有的字符全部写入 fclose(fp); return 0; }
5.fgetc
int fgetc(FILE *stream);
功能:
从流中读取下一个字符
参数:
stream:文件流指针
返回值:
成功返回读到字符的ASCII码值(所以接收数据的变量定义为int型)。
失败或者读到文件末尾返回EOF
#include <stdio.h> int main(void) { FILE *fp = NULL; int ch = 0;//因为返回的是ASCII的值,所以定义为int型 fp = fopen("file.txt", "r"); if (NULL == fp) { perror("fail to fopen"); return -1; } while (1) { ch = fgetc(fp); if (EOF == ch) { break; } printf("%c", ch);//因为是自动获取下一个所以不需要地址跳转下一个地址的代码 } fclose(fp); return 0; }
等价
ch = getchar();//在终端中得到字符
ch = fgetc(stdin);//在文件流中得到字符
putchar(ch);//给终端输入字符
fputc(ch, stdout);//给文件流输入字符
作业:
1.编写一个程序将a.txt文件中的所有内容拷贝到b.txt文件中
2.编写一个程序,从终端输入文件名,统计出该文件内容(纯英文)中出现频率最高的字符及其出现次数
a.txt
6.fgets
char *fgets(char *s, int size, FILE *stream);
功能:
从流中读取一行字符串
参数:
s:用于存放读取到的字符串
size:字符串的长度
stream:文件流指针
返回值:
成功返回存放字符串空间首地址
失败或者读到文件末尾返回NULL
#include <stdio.h> int main(void) { FILE *fp = NULL; char *pret = NULL; char tmpbuff[4096] = {0}; fp = fopen("file.txt", "r"); if (NULL == fp) { perror("fail to fopen"); return -1; } while (1) { pret = fgets(tmpbuff, sizeof(tmpbuff), fp); if (NULL == pret) { break; } printf("%s", tmpbuff); } fclose(fp); return 0; }
7.fputs
int fputs(const char *s, FILE *stream);
功能:
向流中写入一个字符串
参数:
s:字符串的首地址
stream:文件流指针
返回值:
成功返回非负数
失败返回EOF
#include <stdio.h> int main(void) { FILE *fp = NULL; char tmpbuff[1024] = {"how are you"}; fp = fopen("file.txt", "w"); if (NULL == fp) { perror("fail to fopen"); return -1; } fputs("hello world", fp); fputs(tmpbuff, fp); fclose(fp); return 0; }
练习:利用fgets和fputs实现将一个文件中的内容拷贝到另一个文件中
#include <stdio.h> /*************************************************** * 函数名:CopyAsciiFileContent2 * 功 能: * 将srcfile中的文件内容拷贝到dstfile文件中 * 参 数: * dstfile:目的文件的文件路径 * srcfile:源文件的文件路径 * 返回值: * 成功返回0 * 失败返回-1 * 注意事项: * 1.该函数只能拷贝ASCII普通文件内容 **************************************************/ int CopyAsciiFileContent2(const char *dstfile, const char *srcfile) { FILE *fsrc = NULL; FILE *fdst = NULL; char tmpbuff[4096] = {0}; char *pret = NULL; fsrc = fopen(srcfile, "r"); if (NULL == fsrc) { goto err1; } fdst = fopen(dstfile, "w"); if (NULL == fdst) { goto err2; } while (1) { pret = fgets(tmpbuff, sizeof(tmpbuff), fsrc); if (NULL == pret) { break; } fputs(tmpbuff, fdst); } fclose(fsrc); fclose(fdst); return 0; err2: fclose(fsrc); err1: return -1; } int main(void) { char srcfile[256] = {0}; char dstfile[256] = {0}; int ret = 0; ret = CopyAsciiFileContent2("a.txt", "stdio.h"); if (-1 == ret) { printf("拷贝内容失败\n"); } printf("拷贝内容成功\n"); return 0; }
注意:
puts(tmpbuff);
fputs(tmpbuff, stdout);
puts会多打印一个\n字符
gets(tmpbuff);
fgets(tmpbuff, sizeof(tmpbuff), stdin);
gets会去掉用户输入\n字符
fgets不会去掉用户输入的\n字符
#include <stdio.h> #include <string.h> int main(void) { char tmpbuff[1024] = {0}; gets(tmpbuff); printf("tmpbuff = %s\n", tmpbuff); fgets(tmpbuff, sizeof(tmpbuff), stdin); tmpbuff[strlen(tmpbuff)-1] = '\0'; printf("tmpbuff = %s\n", tmpbuff);//去掉fgets接受的\n,强行转为\0. #if 0 puts("hello world"); fputs("hello world", stdout); #endif return 0; }
8.fscanf
int fscanf(FILE *stream, const char *format, ...);
功能:
从流中读取格式化字符串
fscanf(stdin, ...);
scanf(...);
#include <stdio.h> int main(void) { FILE *fp = NULL; int num1 = 0; int num2 = 0; fp = fopen("file.txt", "r"); if (NULL == fp) { perror("fail to fopen"); return -1; } fscanf(fp, "num1 = %d, num2 = %d", &num1, &num2); fclose(fp); printf("num1 = %d, num2 = %d\n", num1, num2); return 0; }
注意:fscanf目标文件的内容的时候,格式必须和文件里的内容一致,使用起来比较繁琐。
9.fprintf
int fprintf(FILE *stream, const char *format, ...);
功能:
向流中写入格式化字符串
fprintf(stdout, ...);
printf(...);
#include <stdio.h> int main(void) { FILE *fp = NULL; int num1 = 100; int num2 = 200; fp = fopen("file.txt", "w"); if (NULL == fp) { perror("fail to fopen"); return -1; } fprintf(fp, "hello world\nnum1 = %d, num2 = %d\n", num1, num2); fclose(fp); return 0; }
练习:
将score.csv中每个学生的成绩获得平均值逐行写入到avg.csv中
#include <stdio.h> int main(void) { FILE *fsrc = NULL; FILE *fdst = NULL; int score1 = 0; int score2 = 0; int score3 = 0; double avgscore = 0; int ret = 0; fsrc = fopen("score.csv", "r"); if (NULL == fsrc) { perror("fail to fopen"); return -1; } fdst = fopen("avg.csv", "w"); if (NULL == fdst) { perror("fail to fopen"); fclose(fsrc); return -1; } while (1) { ret = fscanf(fsrc, "%d,%d,%d", &score1, &score2, &score3); if (EOF == ret) { break; } avgscore = (score1 + score2 + score3) / 3.0; fprintf(fdst, "%.2lf\n", avgscore); } fclose(fsrc); fclose(fdst); return 0;
技巧:在使用fprintf和fscanf的时候,可以先像写printf和scanf的时候的格式写,之后在补充目标文件流。
10.fread
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
从流中读取nmemb个对象,每个对象size个字节,在ptr指向的空间中存放
参数:
ptr:存放数据空间的首地址
size:每个对象的大小
nmemb:写入对象的个数
stream:文件流指针
返回值:
成功返回实际读取对象的个数(最好用size_t 类型的变量接收)
失败或者读到文件末尾返回0
#include <stdio.h> typedef struct student { char name[32]; char sex; int age; int score; }stu_t; int main(void) { FILE *fp = NULL; stu_t temp; stu_t s[4]; int i = 0; size_t nret = 0; fp = fopen("file.txt", "r"); if (NULL == fp) { perror("fail to fopen"); return -1; } nret = fread(s, sizeof(stu_t), 4, fp); for (i = 0; i < nret; i++) { printf("姓名:%s\n", s[i].name); printf("性别:%c\n", s[i].sex); printf("年龄:%d\n", s[i].age); printf("成绩:%d\n", s[i].score); } fclose(fp); return 0; }
11.fwrite
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:
向流中写入nmemb个对象,每个对象size个字节,在ptr指向的空间中存放
参数:
ptr:写入数据空间的首地址
size:每个对象的大小
nmemb:写入对象的个数
stream:文件流指针
返回值:
成功返回实际写入对象的个数
失败返回0
#include <stdio.h> typedef struct student { char name[32]; char sex; int age; int score; }stu_t; int main(void) { FILE *fp = NULL; stu_t a = {"张三", 'm', 19, 100}; stu_t b = {"李四", 'f', 18, 90}; stu_t s[2] = { {"王二", 'm', 16, 90}, {"赵五", 'f', 14, 30}, }; size_t nret = 0; fp = fopen("file.txt", "w"); if (NULL == fp) { perror("fail to fopen"); return -1; } nret = fwrite(&a, sizeof(a), 1, fp); printf("nret = %ld\n", nret); nret = fwrite(&b, sizeof(b), 1, fp); printf("nret = %ld\n", nret); nret = fwrite(s, sizeof(stu_t), 2, fp); printf("nret = %ld\n", nret); fclose(fp); return 0; }
作业:
1.从终端输入一个单词,打印出该单词的含义
练习:
1.利用fread和fwrite实现文件的拷贝
char tmpbuff[4096];
图片的拷贝
#include <stdio.h> int main(void) { FILE *fsrc = NULL; FILE *fdst = NULL; size_t nret = 0; char tmpbuff[4096] = {0}; //打开源文件 fsrc = fopen("src.jpg", "r"); if (NULL == fsrc) { perror("fail to fopen"); return -1; } //打开目的文件 fdst = fopen("dst.jpg", "w"); if (NULL == fdst) { perror("fail to fopen"); fclose(fsrc); return -1; } while (1) { nret = fread(tmpbuff, 1, sizeof(tmpbuff), fsrc); if (0 == nret) { break; } fwrite(tmpbuff, 1, nret, fdst); } fclose(fsrc); fclose(fdst); return 0; }
2.标准IO
1.打开文件 fopen
2.读写文件 fgetc fputc
fgets fputs
fscanf fprintf
fread fwrite
3.关闭文件 fclose
12.fseek
流的定位
偏移量:读和写都在偏移量的位置进行
int fseek(FILE *stream, long offset, int whence);
功能:
设置流的偏移量
参数:
stream:文件流指针
offset:偏移量
whence:
SEEK_SET 文件开头
SEEK_CUR 当前位置
SEEK_END 文件结尾
返回值:
成功返回当前偏移量
失败返回-1
#include <stdio.h> int main(void) { FILE *fp = NULL; fp = fopen("file.txt", "w"); if (NULL == fp) { perror("fail to fopen"); return -1; } fseek(fp, 10, SEEK_SET); fputc('a', fp); fseek(fp, -5, SEEK_CUR); fputc('b', fp); fseek(fp, 0, SEEK_SET); fputc('c', fp); fclose(fp); return 0; }
13.ftell
long ftell(FILE *stream);
功能:
获取流的偏移量
#include <stdio.h> int main(void) { FILE *fp = NULL; long len = 0; fp = fopen("/usr/include/stdio.h", "r"); if (NULL == fp) { perror("fail to fopen"); return -1; } fseek(fp, 0, SEEK_END); len = ftell(fp); printf("len = %ld\n", len); fclose(fp); return 0; }
14.rewind
void rewind(FILE *stream);
功能:
将流的偏移量重新设置到开头
fseek(fp, 0, SEEK_SET);
练习:
编写程序随便给定一个bmp图片文件名获得图片的宽度和高度
#include <stdio.h> int main(void) { FILE *fp = NULL; int width = 0; int height = 0; fp = fopen("suibian.bmp", "r"); if (NULL == fp) { perror("fail to fopen"); return -1; } fseek(fp, 18, SEEK_SET); fread(&width, 4, 1, fp); fread(&height, 4, 1, fp); fclose(fp); printf("宽度:%d 高度:%d\n", width, height); return 0; }