文件操作

文件操作

文件操作的实现将帮助我们把数据存储到文件中,既硬盘上的文件,如我们所熟知的txt格式,或其他各种后缀的文件,避免程序结束后数据丢失,实现存储数据的功能,甚至充当“数据库”的功能。

操作文件的步骤简单来说分为三步

第一步:打开文件

第二步:读写文件

第三步:关闭文件

第一步可以通过fopen函数来实现,这一步作用主要是建立程序和文件的关系,获取文件在内存中的文件指针,方便后面两步。

第二步读写文件分为fprintffscanf或者fwritefread或者fputsgetss等多组函数来实现。

每组函数都分别是写和读文件。就像我们熟知的printf和scanf这组输入输出文件一样,这不过这里的读写不是向屏幕,而是向文件。

第三步关闭文件则需要fclose函数实现。

这一步则是切断文件指针和文件的关联,避免误操作。如果未关闭文件就对文件进行读写删除等操作,就是出现类似“正在被使用,无法修改”的提示

在C语言中,对文件操作之前,首先需要打开文件,使用的函数是fopen函数,它的作用是打开文件,获取该文件的文件指针,方便后续操作。函数原型为:

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

可以看得出来,该函数需要两个字符串类型的参数,第一个是文件名,既要操作的文件对象。第二个是打开方式,这里的打开方式只是,对文件以何种模式打开,包括文本模式打开还是二进制打开、是读还是写还是追加等等等等,具体类型如下表,可以根据情况使用:

参数 作用
r 以只读方式打开文件,该文件必须存在。
r+ 以读/写方式打开文件,该文件必须存在。
rb+ 以读/写方式打开一个二进制文件,只允许读/写数据。
rt+ 以读/写方式打开一个文本文件,允许读和写。
w 打开只写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
w+ 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失;若文件不存在则创建该文件。
a 以附加的方式打开只写文件。若文件不存在,则会创建该文件;如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF 符保留)。
a+ 以附加方式打开可读/写的文件。若文件不存在,则会创建该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(EOF符不保留)。
wb 以只写方式打开或新建一个二进制文件,只允许写数据。
wb+ 以读/写方式打开或新建一个二进制文件,允许读和写。
wt+ 以读/写方式打开或新建一个文本文件,允许读和写。
at+ 以读/写方式打开一个文本文件,允许读或在文本末追加数据。
ab+ 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。

函数的返回值则表示打开成功后的文件指针,格式为FILE类型,是一个结构体类型,供后面使用,如果打开失败,则返回NULL。

比如:如果我们现在想打开一个D盘根目录下的abc.dat,并且想读出该文件里的数据,那么我们可以这样写:

1
2
3
FILE *fp;
fp=fopen("d:\\abc.dat","r")
//后面通过fp指针开始读文件

注意事项

  1. 该文件的目录是绝对路径,因此这样写,如果不写盘符比如abc.dat则表示相对路径,表示与本程序同目录下。
  2. 路径中的反斜杠虽然只有一个,但这里打了两个,原因在于C语言字符串中对反斜杠要当作转义字符处理,因此要用两个反斜杠才能表示一个。
  3. 一旦以r也就是只读的方式打开文件,后面则不允许写数据,否则会出错,一定要保持一致!

下面来介绍fprintf函数,它的原型是:

1
int fprintf (FILE* stream, const char*format, [argument])

该函数是一个格式化写入的库函数,可以看到,除了长得和printf函数很像以外,参数也非常像,多了一个第一个参数文件指针,即第一步打开文件时得到的文件指针,后面的参数和printf一样,按照指定的格式将数据写入文件。例如:

1
fprintf(fp,"%s","www.dotcpp.com");

这句代码的意思是将字符串”www.dotcpp.com"以%s的格式写入fp所指向的文件中。

控制符 作用
%c 字符
%d 或 %i 有符号十进制整数
%e 使用 e 字符的科学科学记数法(尾数和指数)
%E 使用 E 字符的科学科学记数法(尾数和指数)
%f 十进制浮点数
%g 自动选择 %e 或 %f 中合适的表示法
%G 自动选择 %E 或 %f 中合适的表示法
%o 有符号八进制
%s 字符的字符串
%u 无符号十进制整数
%x 无符号十六进制整数
%X 无符号十六进制整数(大写字母)
%p 指针地址
%n 无输出
% 字符
控制符 作用
%c 字符
%d 或 %i 有符号十进制整数
%e 使用 e 字符的科学科学记数法(尾数和指数)
%E 使用 E 字符的科学科学记数法(尾数和指数)
%f 十进制浮点数
%g 自动选择 %e 或 %f 中合适的表示法
%G 自动选择 %E 或 %f 中合适的表示法
%o 有符号八进制
%s 字符的字符串
%u 无符号十进制整数
%x 无符号十六进制整数
%X 无符号十六进制整数(大写字母)
%p 指针地址
%n 无输出
% 字符
控制符 作用
%c 字符
%d 或 %i 有符号十进制整数
%e 使用 e 字符的科学科学记数法(尾数和指数)
%E 使用 E 字符的科学科学记数法(尾数和指数)
%f 十进制浮点数
%g 自动选择 %e 或 %f 中合适的表示法
%G 自动选择 %E 或 %f 中合适的表示法
%o 有符号八进制
%s 字符的字符串
%u 无符号十进制整数
%x 无符号十六进制整数
%X 无符号十六进制整数(大写字母)
%p 指针地址
%n 无输出
% 字符

fprintf函数虽然和printf函数很像,表示输出,但准确说是是写入的意思,是指程序向文件里写,要清楚数据的流向。

如同printf与scanf的关系一样,fprintf和fscanf也是如此,fprintf负责向文件里写数据,fscanf函数则可以从文件里读数据,它的函数原型如下:

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

作为格式化写数据函数,它的参数同样比scanf也多一个参数,即第一个参数文件指针,表示读取的文件目标,其余参数和scanf一样,按照相应的格式进行读取,返回值表示读取数据的字节数。比如:

1
2
char str[100];
fscanf(fp,"%s",str);

则表示从fp所指向的文件中进行读数据,与空格或换行结束,将结果保存到str数组中。

更多fscanf的格式如下表:

格式 作用
%d 读入一个十进制整数
%i 读入十进制,八进制,十六进制整数,与%d类似,但是在编译时通过数据前置或后置来区分进制,如加入“0x”则是十六进制,加入“0”则为八进制。例如串“031”使用%d时会被算作31,但是使用%i时会算作25
%u 读入一个无符号十进制整数
%f %F %g %G 用来输入实数,可以用小数形式或指数形式输入
%x %x 读入十六进制整数
%o 读入八进制整数
%s 直到遇到一个空格字符(空格字符可以是空白、换行和制表符)
%c 单个字符:读取下一个字符。如果指定了一个不为 1 的宽度 width,函数会读取 width 个字符,并通过参数传递,把它们存储在数组中连续位置。在末尾不会追加空字符

fwrite函数就是写文件的函数,它的函数原型如下:

1
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)

可以看到这个函数的参数有四个:

第一个ptr是要写入的数据的头指针,无符号类型;

第二个参数size是大小,表示每个写入元素的大小,单位是字节;

第三个参数nmemb是个数,以上一个参数为单位的个数;

第四个参数stream就是文件指针,表示往哪里写。

至于返回值,如果成功执行,则返回写入元素的个数,如果不和nmemb相等,则表示出错。

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main ()
{
FILE *fp;
char str[] = "www.dotcpp.com";
fp = fopen( "dotcpp.dat" , "w" );
fwrite(str, sizeof(str) , 1, fp );
fclose(fp);
return(0);
}

如代码所示,程序运行后,并不会在屏幕上有任何显示,而是将str中的字符串写入了dotcpp.dat这个文件中

与fwrite是一对,读文件的函数fread的函数原型如下:

1
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)

fread函数的作用是从文件里读内容到程序中,它的参数意思是:

第一个参数ptr表示盛放内容的首地址

第二个参数size表示每个元素的大小,单位还是字节;

第三个参数nmem表示要读取的元素个数

第四个参数stream表示的是文件指针,即从哪个文件中读取。

返回值则是表示读取元素的个数,与nmemb一致表示读取成功,否则失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char buffer[100];
/* 首先打开文件,读写都可以,假设文件中已经有内容为www.dotcpp.com */
fp = fopen("dotcpp.dat", "w+");
/* 读取并显示数据 */
fread(buffer, 1, 15, fp);
printf("%s\n", buffer);
fclose(fp);
return(0);
}