来源:微信公众号「编程学习基地」
文章目录
文件操作
程序运行产生的数据是存储在内存中的,当程序关闭的时候,数据随之丢失,想要保存数据,需要进行文件操作将数据保存在磁盘中。
缓冲区
在进行文件操作的时候,为了提高存取效率,程序在执行是会提供额外的内存暂时存放数据,这块内存就是缓冲区
例如写入文件时:
FILE*fWrite;
if (!(fWrite = fopen("test.txt", "w")))
{
printf("file was not opened! ");
exit(1);
}
fputc('a');
在这里字符a只是写入到了缓冲区,并没有写入磁盘。当你关闭文件或者缓冲区已满的时候才会写入到磁盘当中,例如进行文件关闭代码:
fclose(fWrite);
文件类型
- 文本文件:例如.txt 、.c 、.cpp文件,人能够看懂
- 二进制文件:以二进制形式写入的文件,除了文本文件外,所有的数据都可以算是二进制文件
路径
- 绝对路径
右键任意文件,点击属性,在位置那一栏里面可以找到该文件的绝对路径
注意!!!注意!!!注意!!!
D:\test D盘下的text文件夹
文件读取时要换成:
D:\\test\\test.txt 两个\\是因为:单独一个\是转义,两个\\才代表'\'
或者
D:/test/test.txt 用这个是为了区分转义字符
- 相对路径
相对路径是相对于工作空间而言的,在windows和Linux下
…/ 表示上级目录
./ 表示当前目录
fWrite = fopen("./test.txt", "w")); //表示当前文件夹下的test.txt文件 ./可忽略
fWrite = fopen("../test.txt", "w")); //表示当前文件的上级目录下的test.txt文件
在程序打包过程中,如果出现程序运行什么都没有,一般是路径弄错了,导致程序找不到图片资源。
程序中一般用的是相对路径寻找文件
文件操作函数
打开关闭文件
FILE*fWrite, *fRead;
//第一种打开文件的方法
if (!(fWrite = fopen("test.txt", "w")))
{
printf("file was not opened! ");
exit(1);
}
//第二种打开文件的方法
fRead = fopen("test.txt", "r");
if (fRead == NULL)
{
printf("file was not opened! ");
exit(1);
}
需要注意的是:
- 文件的打开方式
"t":表示文本文件 rt 一般t可以省略不写
"b":表示二进制文件 rb
"+":表示文件可读写
"r":只能从文件中读数据,该文件必须先存在,否则打开失败
"w":只能向文件写数据,若指定的文件不存在则创建它,如果存在则先删除它再重建一个新文件
"a":向文件增加新数据(不删除原有数据),若文件不存在则打开失败,打开时位置指针移到文件末尾
"r+":可读/写数据,该文件必须先存在,否则打开失败
"w+":可读/写数据,用该模式打开新建一个文件,先向该文件写数据,然后可读取该文件中的数据
"a+":可读/写数据,原来的文件不被删去,位置指针移到文件末尾
- 打开文件之后要判断下是否打开成功
- 记得关闭文件
fclose(fRead);
fclose(fWrite);
字符读写函数 fgetc / fputc
函数原型:
int fputc(
int c, //字符
FILE *stream //文件指针
);
int fgetc(
FILE *stream //文件指针
);
程序示例:
void function()
{
//打开文件
FILE*fWrite, *fRead;
if (!(fWrite = fopen("./test.txt", "w")))
{
printf("file was not opened! ");
exit(1);
}
fRead = fopen("./test.txt", "r");
if (fRead == NULL)
{
printf("file was not opened! ");
exit(1);
}
/*************** fputc *****************/
//写入单个字符
fputc('a', fWrite); //写入字符
//循环写入字符
char arr[128] = "你好,世界!";
//for (int i = 0; i < strlen(arr); i++)
//{
// fputc(arr[i], fWrite);
//}
char *p = arr;
while ((*p != '\0') && fputc(*(p++), fWrite) != EOF);
fclose(fWrite); //一定要记得关闭文件
/*************** fgetc *****************/
//单个读取字符
char ch = fgetc(fRead);
putchar(ch);
rewind(fRead); //将文件内部指针移回文件开头
//循环读取字符
//for (int i = 0; (ch = fgetc(fRead)) != EOF; i++)
//{
// arr[i] = ch;
//}
//puts(arr);
while (!feof(fRead)) //feof函数
{
printf("%c", fgetc(fRead));
}
fclose(fRead);
}
在Linux下看到的效果更明显:
ubuntu@ubuntu:~/work$ ls
main.c
ubuntu@ubuntu:~/work$ gcc main.c -o main.exe
ubuntu@ubuntu:~/work$ ls
main.c main.exe
ubuntu@ubuntu:~/work$ ./main.exe
aa你好,世界!
ubuntu@ubuntu:~/work$ ls
main.c main.exe test.txt
我们可以明显的看到work/目录下在运行main.exe程序之后得到test.txt这个文件
注意:
- 第一步是打开文件fopen,然后判断是否打开成功
- 读写操作要分别用两个文件指针
- 然后进行读写操作,同时对一个文件进行读写操作会出错,当写入操作完成之后再进行读取操作
- EOF是宏定义#define EOF (-1) 文本文件的文件末尾标志
- feof()函数是判断文件指针是否读到文件末尾,到达文件末尾返回一真值
字符串读写函数 fgets / fputs
函数原型:
int fputs(
const char *str, //字符数组
FILE *stream //文件指针
);
char *fgets(
char *str, //字符数组
int numChars, //最多读取的字符个数
FILE *stream //文件指针
);
示例:
//写入
fputs( "Hello world\n", fWrite);
//读取
char arr[128];
while (fgets(arr, 127, fRead) != NULL) //arr至少留一个位置给'\0'
{
puts(arr);
}
格式化读写文件 fprintf / fscanf
函数原型:
int fprintf(
FILE *stream, //文件指针
const char *format [,//字符数组
argument ]...
);
int fscanf(
FILE *stream, //文件指针
const char *format [,//字符数组
argument ]...
);
这两个函数和printf,scnaf类似,示例如下
//写入文件
fprintf(fWrite, "我的学号是%d\n",1001);
char arr[128]="你好,世界!";
fprintf(fWrite,arr);
//读取文件
while (!feof(fRead))
{
fscanf(fRead, arr);
puts(arr);
}
二进制读写文件 fread / fwrite
函数原型:
size_t fwrite(
const void *buffer, //指向要写入的数据的指针
size_t size, //要写入项目的大小,以字节为单位
size_t count, //要写入的最大项目数
FILE *stream //指向FILE结构的指针
);
size_t fread(
void *buffer, //数据的存储位置
size_t size, //项目大小(以字节为单位)
size_t count, //读取的最大项目数
FILE *stream //指向FILE结构的指针
);
在读写结构体的时候强烈推荐这种的读写方式,简单,方便
示例:
#include<stdio.h>
typedef struct student
{
int iId;
int iScore;
}STU;
int main()
{
FILE*fWrite, *fRead;
if (!(fWrite = fopen("test3.dat", "wb")))
{
printf("file was not opened! ");
exit(1);
}
fRead = fopen("test3.dat", "rb");
if (fRead == NULL)
{
printf("file was not opened! ");
exit(1);
}
/*************** fwrite *****************/
STU stu = { 1001,100 };
fwrite(&stu //指向要写入的数据的指针
, sizeof(stu) //项目大小,以字节为单位
, 1 //要写入的最大项目数
, fWrite //指向FILE结构的指针
);
stu.iId = 1002;
fwrite(&stu //指向要写入的数据的指针
, sizeof(stu) //项目大小,以字节为单位
, 1 //要写入的最大项目数
, fWrite //指向FILE结构的指针
);
fclose(fWrite);
/*************** fread *****************/
rewind(fRead); //将文件内部指针移回文件开头
STU temp;
while (1)
{
fread(&temp //指向要写入的数据的指针
, sizeof(STU) //项目大小,以字节为单位。
, 1 //要写入的最大项目数
, fRead //指向FILE结构的指针
);
if (feof(fRead)) break;
printf("id:%d\tscore:%d\n", temp.iId, temp.iScore);
}
fclose(fRead);
return 0;
}
也可以参考下学生信息管理系统里面的读写操作
文件指针的操作
上述所有的文件操作都是顺序读写文件
- rewind
使文件位置标志重新返回文件的开头
rewind(fRead); //相当于你接下来读取的位置为fRead指向文件的开头位置
- fseek
int fseek(
FILE *stream, //指向FILE结构的指针
long offset, //从初始位置开始的字节数
int origin //初始位置
);
其中origin设置有这三个宏
原始值 | 原值 | 含义 |
---|---|---|
SEEK_SET | 0 | 文件的开头 |
SEEK_CUR | 1 | 文件指针的当前位置 |
SEEK_END | 2 | 文件末尾 |
示例:
fseek(fRead,sizeof(STU),SEEK_SET); //将文件指针移到开始位置sizeof(STU)字节处
- ftell
long ftell(
FILE *stream
);
作用:得到文件标志的当前位置
示例:
long index=ftell(fRead); //得到文件指针的位置