zoukankan      html  css  js  c++  java
  • 文件基本操作 (C语言)


    一切皆文件

                                                                                                                           ---Linux


    •  头文件 <stdio.h> 中定义了文件的相关操作
    #include <stdio.h>

    文件操作基本流程:

    打开:fopen

    相关操作

    关闭:fclose

    fopen函数原型:FILE *fopen(const char *filename, const char *mode)

    fopen函数打开filename指定的文件, 并返回一个与之相关联的流。 如果打开操作失败,则返回 NULL

    访问模式mode可以为下列合法值之一:

    "r"          打开文本文件用于读

    "w"         创建文本文件用于写, 并删除已经存在的内容(如果有的话)

    "a"          追加, 打开或创建文本文件,并向文件末尾追加内容

    "r+"        打开文本文件用于更新(即读和写)

    "w+"       创建文本文件用于更新, 并删除已经存在的内容(如果有的话)

    "a+"        追加, 打开或创建文本文件用于更新, 写文件时追加到文件末尾

    ps:如果在上述访问模式之后加上 b , 如 "rb" 或 "w+b" 等,则表示对二进制文件进行操作

    fclose函数原型:int fclose(FILE *fp)

    fclose函数的功能是关闭 fp 指向的文件    正常关闭返回0, 出错时返回非0

    ps:文件操作结束不关闭文件可能丢失数据


    • 什么是文本文件?

    在文本文件中数据是以字符形式呈现的,每个字符占用一个字节,而字节在计算机中又是以ASCII码来识别的

    在存储文本文件时需要先将ASCII码转换为二进制的形式,然后进行存储

    比如存储12的时候会按照字符  '1'  和  '2'  来存储

    '1' 的ASCII码为49  转化为二进制为 00110001      '2' 的ASCII码为50  转化为二进制为 00110010

    存储形式为   [00110001][00110010]

    • 什么是二进制文件?

    二进制文件在存储数据时是直接以二进制的方式进行的, 存储方式与数据在内存中的存储方式相同

    不需要进行转换

    优点:不仅可以提高执行效率(比如从磁盘直接读取到内存不需要数据转换),还可以节约存储空间

    比如存储char类型的数字12则会将其二进制数 00001100直接进行存储

    存储i形式为   [00001100]


    • 文本文件和二进制文件的区别(Windows)

    文本文件:写入的时候会将换行符 ' '(ASCII: 10) 解析为回车符 ' '(ASCII:13)' '(ASCII:10)

                      读取的时候又会将回车符 ' '(ASCII:13)' '(ASCII:10)解析成换行符 ' '(ASCII: 10)

    二进制文件:原样写入读出

    • Linux系统下没有区别

    • 三个特殊的文件

    stdin   :标准输入文件指针,系统分配为键盘

    stdout :标准输出文件指针,系统分配为显示器

    stderr  :标准错误输出文件指针,系统分配为显示器

    在文件操作时,系统自动与3个标准设备文件联系,这3个文件无需打开和关闭

    从文件中输入和向文件输出有两个对应函数:

    fprintf

    函数原型为

    int fprintf (FILE *, const char *, ...);

     fscanf

    函数原型为

    int    fscanf (FILE *, const char *, ...);

     例如 printf("hello world! ");  等价于   fprintf(stdout, "hello world ");

             scanf("%d", &num);  等价于    fscanf(stdin, "%d", &num);

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main()
     5 {
     6     int num;
     7     fscanf(stdin, "%d", &num);
     8     fprintf(stdout, "%d
    ", num);
     9     return 0;
    10 }

    • 文件型结构体

    C语言提供“文件型”结构来标识记录待操作文件的信息,该结构体定义在头文件 stdio.h 中

    形式为:

     1 typedef struct _iobuf
     2  {
     3 char *_ptr;        /*  当前缓冲区内容指针           */
     4 int   _cnt;        /*  缓冲区还有多少个字符          */
     5 char *_base;       /*  缓冲区的起始地址             */
     6 int   _flag;       /*  文件流的状态,是否错误或者结束 */
     7 int   _file;       /*  文件描述符                  */
     8 int   _charbuf;    /*  双字节缓冲,缓冲2个字节       */
     9 int   _bufsiz;     /*  缓冲区大小                  */
    10 char *_tmpfname;   /*  临时文件名                  */
    11 } FILE;

    • 文件基本操作

    打开与关闭文件   fopen   fclose

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define FILE_NAME "./1.txt"     /* 存在的文件   */
     4 #define FILE_NAME_NO "./2.txt"  /* 不存在的文件 */
     5 int main()
     6 {
     7     FILE *fp = fopen(FILE_NAME, "r");
     8     if(!fp){
     9         perror("|open file failed");
    10         return 1;
    11     }
    12     printf("|open the file %s successfully
    ", FILE_NAME);
    13     int i = fclose(fp);                                     /*关闭成功返回 0*/
    14     printf("|%d
    ", i);
    15 
    16     FILE *fp_no = fopen(FILE_NAME_NO, "r");
    17     if(!fp_no){
    18         perror("|open file failed");
    19         return 1;
    20     }
    21     printf("|open the file %s successfully
    ", FILE_NAME_NO);
    22     int j = fclose(fp_no);
    23     printf("|%d
    ", j);
    24     return 0;
    25 }

    输出

    |open the file ./1.txt successfully
    |0
    |open file failed: No such file or directory

    字符读写函数   fgetc   fputc

    函数原型

    1 int    fgetc (FILE *);
    2 
    3 int    fputc (int, FILE *);

     

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define FILE_NAME "./1.txt"     /* 存在的文件   */
     4 int main()
     5 {
     6     FILE *fp = fopen(FILE_NAME, "r");
     7     if(!fp){
     8         perror("|open file failed");
     9         return 1;
    10     }
    11     printf("|open the file %s successfully
    ", FILE_NAME);
    12     char c = fgetc(fp);
    13     printf("|%c
    ", c);
    14     fclose(fp);
    15     return 0;
    16 }

     输出

    |open the file ./1.txt successfully
    |h
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define FILE_NAME "./2.txt"     /* 不存在的文件   */
     4 int main()
     5 {
     6     FILE *fp = fopen(FILE_NAME, "w");
     7     if(!fp){
     8         perror("|open file failed");
     9         return 1;
    10     }
    11     printf("|open the file %s successfully
    ", FILE_NAME);
    12     fputc('h', fp);
    13     fclose(fp);
    14     return 0;
    15 }

     新建了 2.txt文件 并写入一个字符 h

    后续的函数相关操作类似,列出了函数原型,不举代码示例啦(偷懒ing)


    字符串读写函数  fgets      fputs

    函数原型

    1 int    fputs (const char *, FILE *);
    2 
    3 char * fgets (char *, int, FILE *);

    格式化读写函数   fprintf     fscanf

    函数原型

    1 int fprintf (FILE *, const char *, ...);
    2 
    3 int fscanf (FILE *, const char *, ...);

    数据块读写函数   fread      fwrite

    函数原型

    1 size_t fread (void *, size_t, size_t, FILE *);
    2 
    3 size_t fwrite (const void *, size_t, size_t, FILE *);

    这两个函数用于读写数据块,成功返回 块数, 出错或到文件尾返回 0

    第一个参数:  指向要输入/输出数据块的首地址的指针

    第二个参数:  每个要读/写的数据块的大小(字节数)

    第三个参数:   要读/写的数据块的个数

    第四个参数:   要读/写的文件指针

    fread 和 fwrite 函数一般用于 数组  结构体等块的读写(多为二进制形式)

    比如

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #define FILE_NAME "./3.txt"     /* 不存在的文件   */
     4 
     5 int main(){
     6 
     7     int num[50] = {0};
     8     for(int i = 0; i < 50; ++i){
     9         num[i] = i;
    10     }
    11     FILE *fp = fopen(FILE_NAME, "w+b");
    12     fwrite(num, sizeof(int), 50, fp);
    13     printf("指针到达:%d
    ", (int)ftell(fp));
    14     rewind(fp);
    15     printf("指针到达:%d
    ", (int)ftell(fp));
    16     int newnum[50] = {0};
    17     fread(newnum, sizeof(int), 50, fp);
    18     for(int i = 0; i < 50; ++i){
    19         printf(" %d", newnum[i]);
    20     }
    21     printf("
    ");
    22     fclose(fp);
    23     return 0;
    24 }

     得到 3.txt文件 内容:

     

    可以看到一个int类型占有4个字节,并且存储方式是低位在前高位在后

    输出结果:


    判断文件是否结束    feof

    函数原型

    int feof (FILE *);

    feof函数用来判断文件是否结束, 文件结束返回一个 非0值, 未结束则返回 0


    文件出错检验         ferror

    函数原型

    int ferror (FILE *);

    ferror函数用来测试文件是否出错, 未出错返回 0, 出错返回一个 非0值


    文件定位       rewind    fseek   ftell

    函数原型

    1 int    fseek (FILE *, long, int);  /*根据参考位置灵活移动指针到目的地*/
    2 
    3 long   ftell (FILE *);             /*用来告诉我指针距离文件头的字符数*/
    4 
    5 void   rewind (FILE *);            /*将指针重新移动到文件头*/

    其中 fseek函数第一个参数操作的文件指针(fp), 第二个参数是偏移量(offset) 第三个参数是参考点:0---文件开始    2---文件末尾   1---当前位置


    刷新缓冲区    fflush

    函数原型

    int    fflush (FILE *);

    对于输出流来说, fflush函数将已经写到缓冲区但尚未写入文件的所有数据写到文件中

    对输入流来说, 其结果是未定义的

    如果在写的过程中发生错误,则返回EOF, 否则返回 0, fflush(NULL)将清洗所有的输出流


    文件删除      remove

    函数原型

    int    remove (const char *);

    remove函数删除指定的文件, 操作成功返回 0, 操作失败返回一个 非0值


    文件重命名    rename

    函数原型

    int    rename (const char *, const char *);

    修改文件名成功返回 0 , 操作失败返回 非0值


    创建临时文件    tmpfile

    函数原型

    FILE * tmpfile (void);

    tmpfile函数以 "wb+" 模式创建一个临时文件(二进制的形式-->临时文件当然读写更快),该文件在被关闭或程序正常结束时将被自动删除

    创建操作成功 函数返回一个流(文件的指针), 创建文件失败返回NULL


    创建一个临时文件名   tmpnam

    函数原型

    char * tmpnam (char *);

    tmpnam函数创建一个与现有文件名不同的字符串,并返回一个指向一内部静态数组的指针,tmpnam(s)函数把创建的字符串保存到数组s中,并将它作为函数返回值返回

    要注意的是数组s要具有足够的空间来存储这个文件名字符串

    示例

    1 #include <stdio.h>
    2  
    3 int main()
    4 {
    5     char s[64] = {0};
    6     tmpnam(s);
    7     printf("%s
    ", s);
    8     return 0;
    9 }

    输出

    s804.

    这是一个随机的文件名(只要不与现有的冲突就OK) 


    后记:

    -- 在进行文件操作的时候根据情况选择合适的读写方式以及读写格式

    -- 要灵活使用 feof    fflush (!!!!切记缓冲问题)    ftell      fseek     rewind     等函数

    -- 文件使用结束切记 fclose 关闭文件, 避免出错

  • 相关阅读:
    leetcode:655. 输出二叉树
    leetcode:763. 划分字母区间
    leetcode:3. 无重复字符的最长子串
    leetcode:2. 两数相加
    leetcode每日一题:409. 最长回文串
    leetcode:1381. 设计一个支持增量操作的栈
    leetcode:1380. 矩阵中的幸运数
    [数据结构] 迷宫问题(栈和队列,深搜和广搜)
    [数据结构] N皇后问题
    [2011山东ACM省赛] Sequence (动态规划)
  • 原文地址:https://www.cnblogs.com/xinglichao/p/9182182.html
Copyright © 2011-2022 走看看