c语言中文件操作

文件操作步骤

要把大象装进冰箱总共分几步?

一、对文件的操作步骤

1)引入头文件(stdio.h )

2)定义文件指针

3)打开文件

4)文件读写

5)关闭文件

二、有关文件的概念

 按文件的逻辑结构:

记录文件:由具有一定结构的记录组成(定长和不定长)

流式文件:由一个个字符(字节)数据顺序组成

 按存储介质

普通文件:存储介质文件(磁盘、磁带等) 

设备文件:非存储介质(键盘、显示器、打印机等)

 按数据的组织形式:

文本文件: ASCII文件,每个字节存放一个字符的ASCII码

二进制文件:数据按其在内存中的存储形式原样存放

 流概念

流是一个动态的概念,可以将一个字节形象地比喻成一滴水,字节在设备、文件和程序之间的传输就是流,类似于水在管道中的传输,可以看出,流是对输入输出源的一种抽象,也是对传输信息的一种抽象。通过对输入输出源的抽象,屏蔽了设备之间的差异,使程序员能以一种通用的方式进行存储操作,通过对传输信息的抽象,使得所有信息都转化为字节流的形式传输,信息解读的过程与传输过程分离。

C语言中,I/O操作可以简单地看作是从程序移进或移出字节,这种搬运的过程便称为流(stream)。程序只需要关心是否正确地输出了字节数据,以及是否正确地输入了要读取字节数据,特定I/O设备的细节对程序员是隐藏的。

文件处理方法

1)文件缓冲区

ANSI C标准采用“缓冲文件系统”处理数据文件 所谓缓冲文件系统是指系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区 从内存向磁盘输出数据必须先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘去 如果从磁盘向计算机读入数据,则一次从磁盘文件将一批数据输入到内存缓冲区(充满缓冲 ),然后再从缓冲区逐个地将数据送到程序数据区(给程序变量)(DMA方式)

2)输入输出流 

输入输出是数据传送的过程,数据如流水一样从一处流向另一处,因此常将输入输出形象地称为 (stream),即数据流。流表示了信息从源到目的端的流动。

输入操作时,数据从文件流向计算机内存 --- 文件的读取

输出操作时,数据从计算机流向文件 --- 文件的写入

无论是用Word打开或保存文件,还是C程序中的输入输出都是通过操作系统进行的 “流”是一个传输通道,数据可以从运行环境流入程序中,或从程序流至运行环境

 文件句柄(操纵文件的详细信息)

 1 typedef struct
 2 {
 3     short           level;      /* 缓冲区"满"或者"空"的程度 */
 4     unsigned        flags;      /* 文件状态标志 */
 5     char            fd;         /* 文件描述符 */
 6     unsigned char   hold;       /* 如无缓冲区不读取字符 */
 7     short           bsize;      /* 缓冲区的大小 */
 8     unsigned char   *buffer;    /* 数据缓冲区的位置 */
 9     unsigned        ar;         /* 指针,当前的指向 */
10     unsigned        istemp;     /* 临时文件,指示器 */
11     short           token;      /* 用于有效性的检查 */
12 }FILE;

三、C语言文件指针

C语言中用一个指针变量指向一个文件,这个指针称为文件指针。

声明FILE结构体类型的信息包含在头文件“stdio.h”中

一般设置一个指向FILE类型变量的指针变量,然后通过它来引用这些FILE类型中的变量通过文件指针就可对它所指的文件进行各种操作。

定义说明文件指针的一般形式为:

FILE * 指针变量标识符;

其中FILE应为大写,它实际上是由系统定义的一个结构,该结构中含有文件名、文件状态和文件 当前位置等信息。在编写源程序时不必关心FILE结构的细节。

FILE *fp;

表示fp是指向FILE类型结构体的指针变量,通过fp即可找存放某个文件信息的结构变量,然后按结构变量提供的信息找到该文件,实施对文件的操作。习惯上也笼统地把fp称为指向一个文件的指针。

四、文件操作API(接口)

fgetc fputc 按照字符读写文件

fputs fgets   按照行读写文件 (读写配置文件)

fread fwirte 按照块读写文件 (大数据块迁移)

fprintf fscanf 按照格式化进行读写文件

1. 文件的打开fopen()

文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了。当使用打开函数时,必须给出文件名、文件操作方式(读、写或读写),如果该文件名不存在,就意味着建立(只对写文件而言,对读文件则出错),并将文件指针指向文件开头。若已有一个同名文件存在,则删除该文件,若无同名文件,则建立该文件,并将文件指针指向文件开头。

fopen(char *filename,char *type);

其中*filename是要打开文件的文件名指针,一般用双引号括起来的文件名表示,也可使用“+反斜杠隔开的路径名”。而*type参数表示了对打开文件的操作方式。其可采用的操作方式如下:

 

当用fopen()成功的打开一个文件时,该函数将返回一个FILE指针,如果文件打开失败,将返回一个NULL指针。

例如:如想打开test文件,进行写:

 1 FILE *fp;
 2 
 3 if((fp=fopen("test","w"))==NULL)
 4 {
 5     printf("File cannot be    opened
");
 6     exit();
 7 }
 8 else
 9 {
10     printf("File opened for writing
");
11 }
12 
13 fclose(fp);  //(将文件指针指向的文件结构体所申请的空间释放)

c语言中有三个特殊的文件指针无需定义、打开可直接使用:

stdin: 标准输入  默认为当前终端(键盘)

我们使用的scanf、getchar函数默认从此终端获得数据

stdout:标准输出  默认为当前终端(屏幕)

我们使用的printf、puts函数默认输出信息到此终端

stderr:标准出错  默认为当前终端(屏幕)

当我们程序出错或者使用:perror函数时信息打印在此终端

2. 关闭文件函数fclose()

   文件操作完成后,必须要用fclose()函数进行关闭,这是因为对打开的文件进行写入时,若文件缓冲区的空间未被写入的内容填满,这些内容不会写到打开的文件中去而丢失。只有对打开的文件进行关闭操作时,停留在文件缓冲区的内容才能写到该文件中去,从而使文件完整。再者一旦关闭了文件,该文件对应的FILE结构将被释放,从而使关闭的文件得到保护,因为这时对该文件的存取操作将不会进行。文件的关闭也意味着释放了该文件的缓冲区。

int fclose(FILE *stream);

它表示该函数将关闭FILE指针对应的文件,并返回一个整数值。若成功地关闭了文件,则返回一个0值,否则返回一个非0值。常用以下方法进行测试

1 if(fclose(fp)!=0)
2 {
3     printf("File cannot be closed
");
4     exit(1);
5 }
6 else
7 {
8     printf("File is now closed
");
9 }

3. 文件的读写

 (1) 读写文件中字符的函数(一次只读写文件中的一个字符):

1 int fgetc(FILE *stream);
2 int fputc(int ch,FILE *stream);
3 
4 int getc(FILE *stream);
5 int putc(int ch,FILE *stream);

其中fgetc()函数将把由流指针指向的文件中的一个字符读出,例如:

1 ch=fgetc(fp);

将把流指针fp指向的文件中的一个字符读出,并赋给ch,当执行fgetc()函数时,若当时文件指针指到文件尾,即遇到文件结束标志EOF(其对应值为-1),该函数返回一个-1给ch,在程序中常用检查该函数返回值是否为-1来判断是否已读到文件尾,从而决定是否继续。

 1 #include <stdio.h>
 2 
 3 int main(void)
 4 {
 5     FILE *fp;
 6     char ch;
 7     
 8     if((fp=fopen("myfile.txt","r"))==NULL)
 9     {
10         printf("file cannot be opened
");
11         exit(1);
12     }
13     while((ch=fgetc(fp))!=EOF) {
14         fputc(ch,stdout);
15     }
16     
17     fclose(fp);
18 
19     return 0;
20 }

    该程序以只读方式打开myfile.txt文件,在执行while循环时,文件指针每循环一次后移一个字符位置。用fgetc()函数将文件指针指定的字符读到ch变量中,然后用fputc()函数在屏幕上显示,当读到文件结束标志EOF时,变关闭该文件。

上面的程序用到了fputc()函数,该函数将字符变量ch的值写到流指针指定的文件中去,由于流指针用的是标准输出(显示器)的FILE指针stdout,故读出的字符将在显示器上显示。

 (2) 读写文件中字符串的函数

1 char *fgets(char *string,int n,FILE *stream);
2 int fprintf(FILE *stream,char *format, ...);
3 int fputs(char *string,FILE *stream);

其中fgets()函数将把由流指针指定的文件中n-1个字符,读到由指针stream指向的字符数组中去,例如:

fgets(buffer, 9, fp);

将把fp指向的文件中的8个字符读到buffer内存区,buffer可以是定义的字符数组,也可以是动态分配的内存区。

注意:fgets()函数读到' '就停止,而不管是否达到数目要求。同时在读取字符串的最后加上''。

fgets()函数执行完以后,返回一个指向该串的指针。如果读到文件尾或出错,则均返回一个空指针NULL,所以长用feof()函数来测定是否到了文件尾或者是ferror()函数来测试是否出错,例如下面的程序用fgets()函数读test.txt文件中的第一行并显示出来:

 1 #include <stdio.h>
 2 
 3 int main(void)
 4 {
 5     FILE *fp;
 6     char str[128];
 7     
 8     if((fp=fopen("test.txt","r"))==NULL)
 9     {
10         printf("cannot open file
");
11         exit(1);
12     }
13 
14     while(!feof(fp))
15     {
16         if(fgets(str,128,fp)!=NULL) printf("%s",str);
17     }
18     
19     fclose(fp);
20     
21     return 0;
22 }

fputs()函数向指定文件写入一个由string指向的字符串,''不写入文件。                

fprintf()同printf()函数类似,不同之处就是printf()函数是想显示器输出,fprintf()则是向流指针指向的文件输出。

下面程序是向文件test.dat里输入一些字符: 

 1 #include<stdio.h>
 2 
 3 int main(void)
 4 {
 5     char *s="That's good news";
 6     int i=617;
 7     FILE *fp;
 8 
 9     fp=fopen("test.dat", "w");
10 
11     fputs("Your score of TOEFLis",fp);
12 
13     fputc(':', fp);
14     fprintf(fp, "%d
", i);
15     fprintf(fp, "%s", s);
16 
17     fclose(fp);
18 
19     return 0;
20 }

文件中内容:

     Your score of TOEFL is: 617

     That's good news

 

(3) 文件二进制块读写函数

1 #include <stdio.h>
2 
3 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); 
4 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
5 
6 //返回值:读或写的记录数,成功时返回的记录数等于nmemb,
7 //出错或读到文件末尾时返回 的记录数小于nmemb,也可能返回0   

fread和fwrite用于读写记录,这里的记录是指一串固定长度的字节,比如一个int、一个结构体或者一个定长数组。参数size指出一条记录的长度,而nmemb指出要读或写多少条记录,这些 记录在ptr所指的内存空间中连续存放,共占size * nmemb个字节,fread从文件stream中读 size * nmemb个字节保存到ptr中,而fwrite把ptr中的size * nmemb个字节写到文件stream中。

nmemb是请求读或写的记录数,fread和fwrite返回的记录数有可能小于nmemb指定的记录数。例 如当前读写位置距文件末尾只有一条记录的长度,调用fread时指定nmemb为2,则返回值为1 如果当前读写位置已经在文件末尾了,或者读文件时出错了,则fread返回0。如果写文件时出 错了,则fwrite的返回值小于nmemb指定的值。下面的例子由两个程序组成,一个程序把结构体 保存到文件中,另一个程序和从文件中读出结构体。

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 struct record {
 5     char name[10];
 6     int age;
 7 };
 8 
 9 int main(void)
10 {
11     struct record array[2];
12 
13     FILE *fp = fopen("recfile", "r"); 
14 
15     if (fp == NULL) {
16         printf("Open file recfile");
17         exit(1);
18     }
19 
20     fread(array, sizeof(struct record), 2, fp); 
21     printf("Name1: %s	Age1: %d
", array[0].name, array[0].age);
22     rintf("Name2: %s	Age2: %d
", array[1].name, array[1].age);
23 
24     fclose(fp);
25 
26     return 0;
27 }

4. 清除和设置文件缓冲区

int fflush(FILE *stream);

fflush()函数将清除由stream指向的文件缓冲区里的内容,常用于写完一些数据后,立即用该函数清除缓冲区,以免误操作时,破坏原来的数据。

5. 文件的随机读写函数

1 #include <stdio.h>
2 
3 int fseek(FILE *stream, long offset, int whence);
4 //返回值:成功返回0,出错返回-1并设置errno 
5 
6 long ftell(FILE *stream);
7 //返回值:成功返回当前读写位置,出错返回-1并设置errno 
8 
9 void rewind(FILE *stream);

fseek的whence和offset参数共同决定了读写位置移动到何处,whence参数的含义如下:

SEEK_SET

从文件开头移动offset个字节

SEEK_CUR

从当前位置移动offset个字节

SEEK_END  

从文件末尾移动offset个字节 

offset可正可负,负值表示向前(向文件开头的方向)移动,正值表示向后(向文件末尾的方 )移动,如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了 文件末尾,再次写入时将增大文件尺寸,从原来的文件末尾到fseek移动之后的读写位置之间的 字节都是0。 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4 int main(void)
 5 {
 6     FILE* fp;
 7 
 8     if ( (fp = fopen("textfile","r+")) == NULL) {
 9         printf("Open file textfile
”);
10         exit(1);
11     }
12 
13     if (fseek(fp, 10, SEEK_SET) != 0) {
14         printf("Seek file textfile
");
15         exit(1);
16     }
17 
18     fputc('K', fp);
19     fclose(fp);
20 
21     return 0;
22 }

文件操作案例

1)配置文件读写(自定义接口)

配置文件读写案例实现分析

  1、 功能划分

  a) 界面测试(功能集成)

    自己动手规划接口模型。

  b) 配置文件读写

    i. 配置文件读(根据key,读取valude)

    ii. 配置文件写(输入key、valude)

    iii. 配置文件修改(输入key、valude)

    iv. 优化 ===》接口要求紧 模块要求松

  2、 实现及代码讲解

  3、 测试。 

(2)加密文件读写 (使用别人写好的接口)

 

原文地址:https://www.cnblogs.com/zhj868/p/13642323.html