C语言文件操作
什么是文件
在程序设计中,我们谈的文件一般有2种
程序文件
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
今天介绍的就是用VS进行数据文件的读写
文件名
一个文件要有唯一的标识,以便用户识别和引用
文件名包含3部分:文件路径+文件名主干+文件后缀
如:c:\code\test.txt
文件流
流在文件操作中,是一个高度抽象的概念
它解决的问题是:数据怎么在内存与外部设备之间流动的
我们知道,现实中,水的流动叫水流,电的流动叫电流
这些流都会从一个固定的起点到达一个固定的终点
文件操作中的文件流也一样,也有固定的流向,我们把它叫做输入流,输出流
我们对应的文件操作,它的流向是数据->文件->内存
其中,数据从数据端流向文件,称为输出,也就是写操作(write)
数据从文件流向内存,称为输入,也就是读操作(read)
文件缓冲区
ANSIC标准采用"缓冲文件系统"处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块"文件缓冲区"。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
简单来说,就是先存一定的数据,然后再发送
文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量:
FILE* pf;//文件指针变量
文件相关函数的介绍
文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。
FILE * fopen ( const char * filename, const char * mode );//mode为文件打开方式
int fclose ( FILE * stream );
打开方式 | 含义 |
---|---|
“r” | 为了输入数据,打开一个已经存在的文本文件(读) |
“w” | 为了输出数据,打开一个文本文件(写) |
“a” | 向文本文件尾添加数据(追加) |
举例
#define _CRT_SECURE_NO_WARNINGS//VS编译器不加行fopen函数会警告
#include<stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");//用读的方式打开文件
if (pf == NULL)//检测是否打开失败
{
perror("fopen");
return -1;
}
fclose(pf);//关闭文件
return 0;
}
提示没有找到文件,因为我们没有创建
我们在此目录下创建一个
没有任何提示,说明成功打开。
那如果我们把文件放到桌面会怎么样呢?
打开失败
我们右键文件,属性,找到路径
#define _CRT_SECURE_NO_WARNINGS//VS编译器不加行fopen函数会警告
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return -1;
}
fclose(pf);
return 0;
}
在\前多加1个\进行转义。
打开成功
接下来我们用w的方式打开
#define _CRT_SECURE_NO_WARNINGS//VS编译器不加行fopen函数会警告
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "w");//r改成w
if (pf == NULL)
{
perror("fopen");
return -1;
}
fclose(pf);
return 0;
}
会打开成功,如果我们此时把桌面上的data.txt删了,再运行代码会怎么样?
会在桌面新建一个data.txt,这就是不一样的地方。
相关函数介绍
功能 | 函数名 |
---|---|
字符输入函数 | fgetc |
字符输出函数 | fputc |
文本行输入函数 | fgets |
文本行输出函数 | fputs |
格式化输入函数 | fscanf |
格式化输出函数 | fprintf |
二进制输入 | fread |
二进制输出 | fwrite |
fputc
为字符输入函数
int fputc (int c, FILE *fp)
举例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return -1;
}
fputc('A', pf);
fputc('b', pf);
fputc('c', pf);
fclose(pf);
re
turn 0;
}
fgetc
字符输入函数
int fgetc(FILE *stream)
举例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "r");//w改成r
if (pf == NULL)
{
perror("fopen");
return -1;
}
int ch = fgetc(pf);//fgetc返回的是int,用int接收
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
return 0;
}
fputs
int fputs(const char *str, FILE *stream);
举例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return -1;
}
fputs("hello world", pf);
fclose(pf);
return 0;
}
fgets
char *fgets(char *str, int n, FILE *stream)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "r");//w改成r
if (pf == NULL)
{
perror("fopen");
return -1;
}
char arr[20] = { 0 };
fgets(arr, 5, pf);
printf("%s\n", arr);
fgets(arr, 5, pf);
printf("%s\n", arr);
fclose(pf);
return 0;
}
**我们把char *fgets(char *str, int n, FILE *stream)之中的n改成5,但实际只读n-1,也就是4个字符,因为其中放了’\0’**这就是fgets函数的细节
fprintf
格式化输出函数
跟printf比较
int fprintf( FILE *stream, const char *format, [ argument ]…)
int printf( const char *format, [ argument ]… );
只是多了一个文件指针,和前面所介绍的函数一样。在普通函数面前多了一个f字母。
举例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
int n;
double d;
};
int main()
{
struct S s = { 100,3.14 };
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return -1;
}
fprintf(pf, "%d %lf", s.n, s.d);
fclose(pf);
return 0;
}
fscanf
格式化输入函数
int fscanf(FILE *stream, char *format[,argument…]);
举例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
int n;
double d;
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return -1;
}
fscanf(pf, "%d %lf", &(s.n),&(s.d));
printf("%d %lf\n", s.n,s.d);
fclose(pf);
return 0;
}
fwrite和fread
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
二进制输入和输出
举例
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
int n;
double d;
char name[10];
};
int main()
{
struct S s = { 100,3.14,"zhangsan" };
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "wb");//wb:为了输出数据,打开一个二进制文件
if (pf == NULL)
{
perror("fopen");
return -1;
}
fwrite(&s, sizeof(s), 1, pf);
fclose(pf);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
struct S
{
int n;
double d;
char name[10];
};
int main()
{
struct S s = { 0 };
FILE* pf = fopen("C:\\Users\\10847\\Desktop\\data.txt", "rb");//rb:为了输入数据,打开一个二进制文件
if (pf == NULL)
{
perror("fopen");
return -1;
}
fread(&s, sizeof(s), 1, pf);
printf("%d %lf %s\n", s.n, s.d, s.name);
fclose(pf);
return 0;
}