文件基本操作 (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)

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

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

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

  • Linux系统下没有区别

  • 三个特殊的文件

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

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

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

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

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

fprintf

函数原型为

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

 fscanf

函数原型为

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

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

         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\n", 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\n", FILE_NAME);
13     int i = fclose(fp);                                     /*关闭成功返回 0*/
14     printf("|%d\n", 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\n", FILE_NAME_NO);
22     int j = fclose(fp_no);
23     printf("|%d\n", 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\n", FILE_NAME);
12     char c = fgetc(fp);
13     printf("|%c\n", 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\n", 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\n", (int)ftell(fp));
14     rewind(fp);
15     printf("指针到达:%d\n", (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("\n");
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\n", s);
8     return 0;
9 }

输出

\s804.

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


后记:

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

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

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

 

posted @ 2018-06-15 16:36  xinglichao  阅读(5702)  评论(0编辑  收藏  举报