• C语言文件操作——打开 &关闭 &顺序读写 &随机读写


    1.文件的打开和关闭

    1.1 文件指针

    在打开一个文件的时候,会创建一个文件信息区,而文件指针指向的内容就是文件信息区。

    文件信息区中存储的到底是什么内容的,我们可以在VS2013中查看一下文件信息区的内容(不同编译器下有所差异)。

    1. struct _iobuf {
    2. char* _ptr;
    3. int _cnt;
    4. char* _base;
    5. int _flag;
    6. int _file;
    7. int _charbuf;
    8. int _bufsiz;
    9. char* _tmpfname;
    10. };
    11. typedef struct _iobuf FILE;

    文件指针pf的类型是FILE*:

    FILE* pf;//文件指针

    1.2 文件的打开和关闭 

    文件的打开和关闭我们都知道怎么操作,但是如果在编程语言中提到打开关闭文件,我们可能就一无所知了。

    下面介绍两个函数:

    1. //打开文件的函数fopen
    2. FILE * fopen ( const char * filename, const char * mode );
    3. //关闭文件的函数fclose
    4. int fclose ( FILE * stream );

    fopen中有一个参数mode,这个参数其实对应的是打开方式;打开文件有很多种方式,比较常用的只有三种:

    文件使用方式含义如果指定的文件不存在
    r(只读)读取一个已经存在的文本文件出错
    w(只写)打开一个文本文件,输出数据,打开文件之前会先清空文件内容建立新文件
    a (追加)向文本文件末尾添加数据,原来文件中的数据保留,新的数据添加到文件为,原文件EOF保留建立新文件

     演示fopen和fclose的使用:

    1. int main()
    2. {
    3. //打开文件
    4. FILE* pf = fopen("test.txt", "w");
    5. //关闭文件
    6. fclose(pf);
    7. pf = NULL;
    8. return 0;
    9. }

    2.文件的顺序读写

    打开文件的目的是对文件进行读写,四个常用的文件读写函数:

    功能函数名适用于
    字符输入函数fgetc所有输入流
    字符输出函数fputc所有输出流
    文本行输入函数fgets所有输入流
    文本行输出函数fputs所有输出流

    2.1 fputc 

    1. int fputc( int c, FILE *stream );//Writes a character to a stream (fputc, fputwc) or to stdout (_fputchar, _fputwchar).

    fopen创建的文件默认在当前路径下;

    1. void test_fputc()
    2. {
    3. FILE* pf = fopen("test.txt", "w");
    4. //fputc的使用 两个参数-第一个为输出到文件的字符,第二个为输出的文件流
    5. for (int ch = 'a'; ch <= 'z'; ch++)
    6. {
    7. fputc(ch, pf);//输出26个英文字母
    8. }
    9. fclose(pf);
    10. }

    fputc每次只能输出单个字符,想要输出多个字符需要借助循环。 

     

      

    2.2 fgetc

    int fgetc( FILE *stream );

    fputc是把字符输出到文件,fgetc则是把文件中的内容读出来;从用法上来说fgetc的使用更加简单。

    1. void test_fgetc()
    2. {
    3. FILE* pf = fopen("test.txt", "r");//读取test.txt中的内容
    4. //使用fgetc读数据
    5. char ch;
    6. while((ch = fgetc(pf)) != EOF)
    7. {
    8. printf("%c ", ch);
    9. }
    10. fclose(pf);
    11. }

    使用fgetc也是可以读取成功的,而且每次读取之后文件指针也是会向后移动的。 

    2.3 fputs

    单个字符的输入和输出会很麻烦,那么可不可以以字符串的形式输出和输入呢?

    答案是可以的,那就是使用fputs和fgets。

    int fputs( const char *string, FILE *stream );

    fputs在使用上还是很简单的:

    1. void test_fputs()
    2. {
    3. FILE* pf = fopen("mytest.txt", "w");
    4. //使用fputs将字符输出到文件中 两个参数-第一个为常量字符串,第二个为输出的文件流指针
    5. fputs("this is a test\n", pf);
    6. fclose(pf);
    7. }

      

    2.4 fgets

    fgets和fputs作用相反,fgets用来读取文件中的数据到程序中:

    1. char *fgets( char *string, int n, FILE *stream );
    2. //fgets有三个参数,string为读取到的内存区域,n表示读取的最大字符个数,stream为文件指针
    1. void test_fgets()
    2. {
    3. FILE* pf = fopen("mytest.txt", "r");//读数据
    4. //fgets
    5. char buf[101] = { 0 };
    6. printf("%s\n", fgets(buf, 101, pf));
    7. fclose(pf);
    8. }

    3.两组函数的对比

    3.1 scanf &fscanf &sscanf

    函数的参数:

    scanf:  int scanf( const char *format [,argument]... );

    fscanf:  int fscanf( FILE *stream, const char *format [, argument ]... );

    sscanf:  int sscanf( const char *buffer, const char *format [, argument ] ... );

    针对的输入流:

    scanf  :格式化的输入函数

    fscanf :所有输入流

    sscanf:把一个字符串转换成格式化的数据

     sscanf使用示例:

    1. struct S
    2. {
    3. char name[20];
    4. int age;
    5. double grade;
    6. };
    7. int main()
    8. {
    9. char buf[256] = { 0 };
    10. struct S tmp = { 0 };
    11. struct S s = { "zhangsan", 50, 50.8 };
    12. sprintf(buf, "%s %d %lf", s.name, s.age, s.grade);//把结构体中的数据转化为字符串
    13. //从buf中提取一个结构体对象
    14. sscanf(buf, "%s %d %lf", tmp.name, &(tmp.age), &(tmp.grade));
    15. printf("%s %d %f", tmp.name, tmp.age, tmp.grade);
    16. return 0;
    17. }

    3.2 printf &fprintf & sprintf

    函数参数:

    printf:  int printf( const char *format [, argument]... );

    fprintf:  int fprintf( FILE *stream, const char *format [, argument ]...);

    sprintf:  int sprintf( char *buffer, const char *format [, argument] ... );

    针对的输出流:

    printf   : 格式化的输出函数

    fprintf  : 针对所有输出流的格式化输出函数

    sprintf : 把一个格式化的数据转化成字符串

     fprintf使用示例:

    1. struct S
    2. {
    3. char name[20];
    4. int age;
    5. double grade;
    6. };
    7. int main()
    8. {
    9. struct S s = { "张三", 50, 50.8 };
    10. FILE* pf = fopen("test.txt", "w");
    11. fprintf(pf, "%s %d %lf", s.name, s.age, s.grade);
    12. fclose(pf);
    13. pf = NULL;
    14. return 0;
    15. }

    sprintf使用示例:

    1. struct S
    2. {
    3. char name[20];
    4. int age;
    5. double grade;
    6. };
    7. int main()
    8. {
    9. char buf[256] = { 0 };
    10. struct S s = { "zhangsan", 50, 50.8 };
    11. sprintf(buf, "%s %d %lf", s.name, s.age, s.grade);
    12. printf("%s\n", buf);
    13. return 0;
    14. }

    4.文件的随机读写

    4.1 fseek

    int fseek( FILE *stream, long offset, int origin );

    fseek是根据文件指针的偏移量来进行随机读写。

    origin的三种情况:

    SEEK_CUR:文件指针的当前位置

    SEEK_END:文件结束位置

    SEEK_SET:文件开始位置

    若origin使用SEEK_CUR,offset不能为负数;若origin使用SEEK_END,offset不能为正。

    1. void test_fseek()
    2. {
    3. FILE* pFile = fopen("example.txt", "w");
    4. //写文件
    5. fputs("This is an apple.", pFile);
    6. //偏移
    7. fseek(pFile, 9, SEEK_SET);
    8. //关闭文件
    9. fputs(" sam", pFile);
    10. fclose(pFile);
    11. pFile = NULL;
    12. }

     

    下面解释一下为什么是这个结果:

     

    4.2 ftell

    返回文件指针相对于起始位置的偏移量,返回类型为long。

    long int ftell ( FILE * stream );

    示例:

    1. void test_ftell()
    2. {
    3. //打开文件
    4. FILE* pf = fopen("test.txt", "w");
    5. //随机读
    6. fputc('a', pf);
    7. fputc('b', pf);
    8. long pos = ftell(pf);
    9. printf("%d\n", pos);
    10. //关闭文件
    11. fclose(pf);
    12. pf = NULL;
    13. }

     4.3 rewind

    让文件指针的位置回到文件的起始位置。

    void rewind ( FILE * stream );

    示例:

    1. int main()
    2. {
    3. FILE* pf = fopen("test.txt", "w");
    4. fputc('a', pf);
    5. fputc('b', pf);
    6. long pos = ftell(pf);//2
    7. printf("%d\n", pos);
    8. rewind(pf);
    9. pos = ftell(pf);
    10. printf("%ld", pos);//回到起始位置0
    11. fclose(pf);
    12. pf = NULL;
    13. return 0;
    14. }

    总结:文件操作的内容和之前的基础内容相比还是有难度的,主要是一些不常见的函数需要学习使用;然后文件操作部分的代码还是需要自己手动去敲的,不然一段时间之后,再回顾这些内容的时候就会发现已经忘得七七八八了;最后有时间的话可以总结成博客,在复习的时候借助自己的博客是更高效的。

  • 相关阅读:
    Java_位运算符简述
    图文详解Linux基础经典教程(10)——阿里云安装开发工具
    iSlide2024一款基于PPT的插件工具包含38个设计辅助功能
    108 使用Ajax请求获取PHP自制接口
    ZIP压缩文件如何设置密码保护?
    Clion 使用 (Rust)
    apt update和apt upgrade命令 - 有什么区别?
    InnoDB对MVCC的实现
    Python3编程基础-变量与计算器
    SaaSBase:Blue Prism是什么?
  • 原文地址:https://blog.csdn.net/qq_63179783/article/details/124090792