凡是字符串参数都可以替换为字符数组参数

路径

  • Linux下:路径写作"./..."
  • windows下:路径写作如c:\\... 或者 c:/... 盘符大小写都可以
  • 路径不存在必须先创建路径。文件不存在可以自动创建,路径文件夹不会

    windows下的坑

    我的c盘默认就是任何一个位置的更改都需要管理员的权限。那就必须以管理员身份运行ide再编译运行或者直接以管理员身份运行exe文件才能操作成功 否则执行后就没有任何变化

    建立文件流

  • 创建FILE对象并且借助fopen确定路径和访问模式

FILE *fp; fp = fopen("./tmp/test.txt", "w+"); 或者FILE *fp = fopen("./tmp/test.txt", "w+");

  • 借助fopen函数,该函数可以创建一个文件(配合访问模式)并创建文件流或者对一个已经存在的文件创建文件流
    • 如果没有这个文件,访问模式又不允许创建这个文件,文件对象就返回null并且产生一个错误

FILE *fopen( const char * filename, const char * mode );

  • fopen会调用FILE对象,该对象包含所有控制流的信息。
  • filename为文件名
  • mode为访问模式(文件打开方式),有如下参数

带+即表示即可读取又可以写入 | 模式 | 描述 | | —- | —- | | r | 打开一个已有的文本文件,允许读取文件。 | | w | 打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。这个w好像如果存在也会清空再进行写入 | | a | 打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。 追加即末尾开始写入 | | r+ | 打开一个文本文件,允许读写文件。 | | w+ | 打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度(即清空文件内容再写入)如果文件不存在,则会创建一个新文件。 | | a+ | 打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。 即写入时a+等同于a |

如果处理的是二进制文件,则需使用下面的访问模式来取代上面的访问模式:
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
即添加b或者b+ 具体作用见https://blog.csdn.net/observadores/article/details/79305470

读取文件

  • int fgetc( FILE * fp );读取一个字符,位置后移一位,配合循环即可读取全部数据 成功返回字符 失败返回EOF
  • char *fgets( char *buf, int n, FILE *fp ); 读取n - 1 个字符。它会把读取的字符串复制到缓冲区buf,并在最后追加一个null字符来终止字符串。 如果这个函数在读取最后一个字符之前就遇到一个换行符 ‘\n’ 或文件的末尾 EOF,则只会返回读取到的字符,包括换行符。
  • int fscanf(FILE *fp, const char *format, ...) format不清楚是不是缓冲区 该函数读取到空格会停止读取

    关闭文件流

    建立FILE文件流后记得关闭流
    int **fclose**( FILE *fp );

  • 这个函数会清空缓冲区中的数据,关闭文件,并释放用于该文件的所有内存。

  • 如果成功关闭文件,fclose( )函数返回零,如果关闭文件时发生错误,函数返回EOF0

    • EOF为stdio.h中的一个常量

      写入文件

  • int fputc( int c, FILE *fp ); 写入一个字符,位置后移一位

函数fputc()把参数 c 的字符值写入到 fp 所指向的输出流中。如果写入成功,它会返回写入的字符,如果发生错误,则会返回EOF

  • int fputs( const char *s, FILE *fp );把一个以 null 结尾的字符串写入到流中 s为要写入的字符串

写入成功,返回非负值。失败返回EOF

  • int fprintf(FILE *fp,const char *format, ...) 写入一个字符串 format为要写入的字符串

fprintf和fputs差不多,就是2个参数的位置换了下

  1. #include <stdio.h>
  2. int main()
  3. {
  4. FILE *fp;
  5. fp = fopen("c://test.txt", "w+");
  6. fprintf(fp, "This is testing for fprintf...\n");
  7. fputs("This is testing for fputs...\n", fp);
  8. fclose(fp);
  9. }

二进制读取与写入

  • 二进制读取与写入需要给出字符串的元素数和元素大小。

下面两个函数用于二进制输入和输出:

  • size_t fread(void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file; 参考fwrite

size_t fwrite(const void *ptr, size_t size_of_elements, size_t number_of_elements, FILE *a_file);把字符串中的数据写入到文件流当中

  • size_of每个元素的大小(byte单位) number_of为写入元素的个数
    • 记住字符串的元素总数会比看到的个数多1,因为字符串末尾会有一个null字符’\0’
    • 参数number_of可以小于等于字符串长度 即给定看到字符串的个数即可把全部的字符写入文件,不需要再写入’\0’ 给大于字符串的长度则出现c错误(写入些乱码字符)
  • 写入成功返回size-t对象,表示写入元素总数(int型) 如果返回的总数与参数中的总数number不同,即写入发生了错误 ```c

    include

int main () { FILE *fp; char str[] = “This is runoob.com”;

fp = fopen( “file.txt” , “w” ); int b=fwrite(str, sizeof(str) , 4, fp ); //写入4个字符 printf(“%d”,b); fclose(fp); return(0);

//输出b=4=给定的参数4 正确写入 file.txt内容为This }

  1. 这两个函数都是用于存储块的读写 - 通常是数组或结构体。
  2. <a name="Rvd5T"></a>
  3. # 指针位置操作
  4. - `void rewind(FILE *file)`**将位置指针移动至文件的开头 可以用于写入后再移动至开头进行读取**
  5. - `int fseek(FILE *stream, long int offset, int whence)` 将位置指针从whence的位置往后偏移offset个字符 offset即偏移量
  6. - 成功返回0 失败返回非0
  7. - whence可以是如下常量:
  8. | 常量 | 描述 |
  9. | --- | --- |
  10. | SEEK_SET | 文件的开头 |
  11. | SEEK_CUR | 文件指针的当前位置 |
  12. | SEEK_END | 文件的末尾 |
  13. - `fgetpos(FILE *stream, fpos_t *pos)` 获取当前位置并写入到pos
  14. - posfpos_t对象的指针 使用时需要创建一个fpos_t的对象 getpossetpospos参数需要取地址来使用
  15. `fpos_t position; fget/setpos(fp, &position);`
  16. - `fsetpos(FILE *stream, const fpos_t *pos)` 将位置设置为pos参数的位置
  17. ```c
  18. #include <stdio.h>
  19. int main ()
  20. {
  21. FILE *fp;
  22. fpos_t position;
  23. fp = fopen("file.txt","w+");
  24. fgetpos(fp, &position);
  25. fputs("Hello, World!", fp);
  26. fsetpos(fp, &position);
  27. fputs("这将覆盖之前的内容", fp);
  28. fclose(fp);
  29. return(0);
  30. }
  31. 输出为"这将覆盖之前的内容" 因为在创建文件流后位置开始处于开头,使用getpos将开头这个位置写入了position中 写入时也就从开头写入,覆盖掉了helloworld

fseek的注意点

  • 一个字符串他的位置指针是0开始的(毕竟c语言中字符串就是个字符数组) 读写将从偏移到的位置的下一个位置开始
  • 因为w和w+会清空文件进行写入,而a和a+是末尾追加写入 所以如果要覆盖操作就得借助fseek才能覆盖操作

This`` fseek(?,2,SEEK_SET) 是开头偏移了2个字符到i 写入一个字符a将在i后开始操作,得到Thia a覆盖了s

文件状态检测

  • int feof(FILE *stream) 检查文件是否结束(检查位置是否处于结束符’\0’) 如果未结束,返回0 已经结束,返回非0 注意与一般逻辑相反 配合循环和fputc或者fgetc的自动后移一位可以读写文件 ```c

    include

int main () { FILE *fp; int c;

fp = fopen(“file.txt”,”r”); if(fp == NULL) { perror(“打开文件时发生错误”); //如果上一个函数产生错误,则输出错误信息 即如果fopen发生错误(即如果文件不存在,访问模式又不允许创建这个文件,就产生错误) return(-1); } while(1) //无限循环 { c = fgetc(fp); if( feof(fp) ) //fgetc自动后移。如果移动到字符串结尾的’\0’就会返回非0值,则退出无限循环 { break ; } printf(“%c”, c); } fclose(fp); return(0); } ```

文件操作异常处理

  • int ferror(FILE *stream) 如果产生文件操作错误就返回一个非0值
    • 配合if使用可以进行异常处理 如if(ferror(file)){printf("文件操作发生错误");}
  • void clearerr(FILE *stream)文件操作发生错误可以使用该函数进行清楚错误信息(FIlE操作失败可能是文件不存在 或者访问模式与要进行的操作不一致,如只读模式进行写操作)

更多实例

https://www.w3cschool.cn/c/c-file-io.html末尾

总结

  • putc,getc是读写字符 puts和gets是读写字符串
  • printf和scanf是格式化读写字符串
  • write和read是二进制读写字符串