目录
IO:输入输出
1.标准IO
2.特殊的流
3.缓存:
1.全缓存
2.行缓存
3.不缓存
4.函数接口
1.fopen
2.fclose
3.setvbuf
4.fputc
5.fgetc
6.fgets
7.fputs
8.fscanf
9.fprintf
10.fread
11.fwrite
     操作对象:文件
Linux系统一切皆是文件:
             文件分类:
             1.block          b    块设备文件       按块扫描设备信息的文件
             2.char           c     字符设备文件   按字符扫描设备信息的文件 
             3.directory    d     目录文件          保存或管理文件
             4.                  -      普通文件          保存数据信息的文件(代码、图片、音视频、压缩包等)
             5.link             l      链接文件          指向其他文件的文件(类似与window系统的快捷方式) 
             6.socket       s      套接字文件      用于进程间通信 
             7.pipe           p     管道文件          用于进程间通信
     stdio.h  
     主要操作普通文件 
             1.打开文件 
             2.读写文件 
             3.关闭文件 
    默认打开的流
     stdin       标准输入流           行缓存
     stdout      标准输出流          行缓存
     stderr      标准错误流          不缓存
    gets、getchar、scanf是基于stdin实现的
     puts、putchar、printf是基于stdout实现的 
     perror是基于stderr
                 4096  (4k) 
                 缓存区满刷新
         
                 与文件建立的缓存一般为全缓存
                刷新条件:
                     1.缓存区存满了刷新
                     2.fflush函数接口刷新
                     3.关闭流时会刷新(fclose)
                1024  (1k)
                 遇到\n刷新 
与终端建立的缓存都是行缓存
        刷新条件: 
                     1.缓存区满刷新 
                     2.遇到\n刷新 
                     3.fflush函数刷新 
                     4.关闭流时会刷新
        0  0k
         立即刷新 
        刷新条件:
                     1.立即刷新
                    1.对设备的操作不允许缓存
                     2.通信不允许缓存
                     3.出错处理不缓存 
 
               FILE *fopen(const char *pathname, const char *mode);
       功能:
                 打开pathname对应的文件并建立一个文件流
       参数:
                 pathname:文件路径
                 mode:打开方式
                     r      只读             如果文件存在则只读打开
                                             如果文件不存在报错
                     r+     读写             如果文件存在则读写打开
                                             如果文件不存在报错
                     w      只写             如果文件存在则清0,只写打开 
                                             如果文件不存在则创建
                     w+     写读             如果文件存在则清0,读写打开 
                                             如果文件不存在则创建
                     a      追加只写         如果文件存在则追加只写打开 
                                             如果文件不存在则创建
                     a+     追加读写         如果文件存在则追加读写打开 
                                             如果文件不存在则创建
       返回值:
                 成功返回FILE*的指针(所以要定义一个FILE类型的指针去接收返回的指针)
                 失败返回NULL并且将错误码置位 
#include   int main(void) {     FILE *fp = NULL;         fp = fopen("a.txt", "r");  //定义一个指针去接受返回的指针     if (NULL == fp)     {         perror("打开 a.txt 文件失败");  //perror会显示打开失败的原因         return -1;     }                          //判断是否打开失败      return 0; }  
               int fclose(FILE *stream);
       功能:   
                 关闭流 
       参数: 
                 stream:文件流
       返回值:
                 成功返回0 
                 失败返回EOF(-1)
               int setvbuf(FILE *stream, char *buf, int mode, size_t size);
       功能:
                 改变流的缓存类型
       参数:
                 stream:文件流
                 buf:缓存区的首地址 
                 mode:   
                             _IOFBF  全缓存
                             _IOLBF  行缓存
                             _IONBF  不缓存
                 size:缓存区大小
       返回值:
                 成功返回0 
                 失败返回非0 
#include   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; }  
              int fputc(int c, FILE *stream);
       功能:
                 向流中写入一个字符 
       参数:
                 c:写入的字符
                 stream:文件流指针
       返回值:
                 成功返回写入字符的ASCII码值
                 失败返回EOF(-1) 
#include   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   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; }  
               int fgetc(FILE *stream);
       功能:
                 从流中读取下一个字符 
       参数:
                 stream:文件流指针
       返回值:
                 成功返回读到字符的ASCII码值(所以接收数据的变量定义为int型)。
                 失败或者读到文件末尾返回EOF
#include   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 
               char *fgets(char *s, int size, FILE *stream);
        功能:
                  从流中读取一行字符串
        参数:
                   s:用于存放读取到的字符串
                   size:字符串的长度
                   stream:文件流指针
        返回值: 
                  成功返回存放字符串空间首地址
                  失败或者读到文件末尾返回NULL
#include   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; }                int fputs(const char *s, FILE *stream);
       功能:
                 向流中写入一个字符串
       参数:
                 s:字符串的首地址
                 stream:文件流指针 
       返回值: 
                 成功返回非负数
                 失败返回EOF
#include   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  /***************************************************  * 函数名: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  #include   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; }                int fscanf(FILE *stream, const char *format, ...);
     功能:
                 从流中读取格式化字符串
     
             fscanf(stdin, ...);
             scanf(...);
#include   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目标文件的内容的时候,格式必须和文件里的内容一致,使用起来比较繁琐。
            int fprintf(FILE *stream, const char *format, ...);
     功能:
                 向流中写入格式化字符串
     
             fprintf(stdout, ...);
             printf(...);
 #include   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   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的时候的格式写,之后在补充目标文件流。
              size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
       功能:
                 从流中读取nmemb个对象,每个对象size个字节,在ptr指向的空间中存放
       参数:
                 ptr:存放数据空间的首地址
                 size:每个对象的大小
                 nmemb:写入对象的个数
                 stream:文件流指针
       返回值: 
                 成功返回实际读取对象的个数(最好用size_t 类型的变量接收)
                 失败或者读到文件末尾返回0 
#include   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; }                size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
       功能:
                 向流中写入nmemb个对象,每个对象size个字节,在ptr指向的空间中存放
       参数:
                 ptr:写入数据空间的首地址
                 size:每个对象的大小
                 nmemb:写入对象的个数
                 stream:文件流指针
       返回值: 
                 成功返回实际写入对象的个数
                 失败返回0 
#include   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   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
   流的定位
             偏移量:读和写都在偏移量的位置进行
     int fseek(FILE *stream, long offset, int whence);
             功能:
                         设置流的偏移量
             参数:
                         stream:文件流指针
                         offset:偏移量 
                         whence:
                                     SEEK_SET        文件开头
                                     SEEK_CUR        当前位置
                                     SEEK_END        文件结尾
               返回值:
                         成功返回当前偏移量
                         失败返回-1 
#include   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; }          long ftell(FILE *stream);
     功能:
                 获取流的偏移量 
     
 #include   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; }    
     void rewind(FILE *stream);
     功能:
                 将流的偏移量重新设置到开头
fseek(fp, 0, SEEK_SET);
练习:
 编写程序随便给定一个bmp图片文件名获得图片的宽度和高度
#include   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; }