C语言-> 文件操作(函数满屏)
系列文章目录
前言
?作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉
🍎个人主页:橘橙黄又青_C语言,数据结构,函数-CSDN博客
目的:学习文件操作,即文件相关函数的学习
在这里首先放置我个人认为好的学习c语言的网站
:cplusplus.com:https://legacy.cplusplus.com/reference/clibrary/
好了我们现在开始吧?
1. 为什么使??件?
2. 什么是?件?
2.1 程序?件
2.2 数据?件
在以前各章所处理数据的输?输出都是以终端为对象的,即从终端的键盘输?数据,运?结果显?到 显?器上。其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使?,这?处 理的就是磁盘上?件。
2.3 ?件名 ?
c:\ code \ test . txt
3. ?进制?件和?本?件?
#include <stdio.h>
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf);//?进制的形式写到?件中
fclose(pf);
pf = NULL;
return 0;
}
4. ?件的打开和关闭
在此之前先了解一个抽象的概念:
4.1 流和标准流
4.1.1 流
4.1.2 标准流
那为什么我们从键盘输?数据,向屏幕上输出数据,并没有打开流呢?
? stdin - 标准输?流,在?多数的环境中从键盘输?,scanf函数就是从标准输?流中读取数据。? stdout - 标准输出流,?多数的环境中输出?显?器界?,printf函数就是将信息输出到标准输出流中。? stderr - 标准错误流,?多数环境中输出到显?器界?。这是默认打开了这三个流,我们使?scanf、printf等函数就可以直接进?输?输出操作的。
stdin、stdout、stderr 三个流的类型是: FILE* ,通常称为?件指针。?
4.2 ?件指针
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
FILE* pf;//?件指针变量
4.3 ?件的打开和关闭
//打开?件
FILE * fopen ( const char * filename, const char * mode );//两个参数:一个是文件名,一个是文件使用方式
//关闭?件
int fclose ( FILE * stream );
?件使??式
|
含义
|
如果指定?件不存在
|
“r”(只读)
|
为了输?数据,打开?个已经存在的?本?件
|
出错
|
“w”(只写)
|
为了输出数据,打开?个?本?件
|
建??个新的?件
|
“a”(追加)
|
向?本?件尾添加数据
|
建??个新的?件
|
“rb”(只读)
|
为了输?数据,打开?个?进制?件
|
出错
|
“wb”(只写)
|
为了输出数据,打开?个?进制?件
|
建??个新的?件
|
“ab”(追加)
|
向?个?进制?件尾添加数据
|
建??个新的?件
|
“r+”(读写)
|
为了读和写,打开?个?本?件
|
出错
|
“w+”(读写)
|
为了读和写,建议?个新的?件
|
建??个新的?件
|
“a+”(读写)
|
打开?个?件,在?件尾进?读写
|
建??个新的?件
|
“rb+”(读写)
|
为了读和写打开?个?进制?件
|
出错
|
“wb+”(读
写)
|
为了读和写,新建?个新的?进制?件
|
建??个新的?件
|
“ab+”(读
写)
|
打开?个?进制?件,在?件尾进?读和写
|
建??个新的?
|
我们怎么理解读和写看图:
这里我们演示一下打开关闭,实战代码:
/* fopen fclose example */
#include <stdio.h>
int main ()
{
FILE * pFile;
//打开?件
pFile = fopen ("myfile.txt","w");
//?件操作
if (pFile!=NULL)
{
fputs ("fopen example",pFile);
//关闭?件
fclose (pFile);
}
return 0;
}
5. ?件的顺序读写
5.1 顺序读写函数介绍
函数名
|
功能
|
适?于
|
fgetc
|
字符输?函数
|
所有输出流
|
fputc
|
字符输出函数
|
所有输出流
|
fgets
|
?本?输?函数
|
所有输出流
|
fputs
|
?本?输出函数
|
所有输出流
|
fscanf
|
格式化输?函数
|
所有输出流
|
fprintf
|
格式化输出函数
|
所有输出流
|
fread
|
?进制输?
|
?件
|
fwrite
|
?进制输出
|
?件
|
那好我们来一个一个介绍:打开网站:
https://legacy.cplusplus.com/reference/clibrary/
(1)fputc
参数是:文件名和流
代码实现:
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pf = fopen("data.txt", "w");//写入文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputc('a', pf);//写入一个字符'a'
fputc('\n', pf);
fputc('b', pf);
fclose(pf);
return 0;
}
fputc只能一个一个字符的输入,也可以写一个循环输入多个字符。
for (i = 0; i < 26; i++) {
fputc('a' + 1, pf);
fputc('\n', pf);//写完换行
}
(2)fgetc
现在先我们输入字符进“data.txt”文件中,比如说输入:“abcdefg",然后实现代码读操作
代码:
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pf = fopen("data.txt", "r");//写入文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);//读取一个字符
printf("%c", ch);//打印
fclose(pf);
pf = NULL;
return 0;
}
具体操作和输出结果如下:
当然也可以写成循环的形式,但是要注意什么时候结束,比如说:
下面代码:
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pf = fopen("data.txt", "r");//写入文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = 0;
while ((ch = fgetc(pf)) != ' ') {
printf("%c", ch);//打印
}
fclose(pf);
pf = NULL;
return 0;
}
两种情况:
这就要看文件文本句末了,避免造成死循环。
接下来我们学习一个复制文件内容的操作:
假设文件里面有代码
代码实现:
//从data.txt中读取数据
//写到data2.txt的文件中
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pfread = fopen("data.txt", "r");//读
if (pfread == NULL)
{
perror("fopen->data1.txt");//报错详细一点
return 1;
}
FILE* pfwrite = fopen("data2.txt", "w");//写
if (pfwrite == NULL)
{
fclose(pfread);//如果出现错误先关闭打开文件
pfread = NULL;
perror("fopen->data2.txt");
return 1;
}
//数据的读写(拷贝)
int ch = 0;
while ((ch = fgetc(pfread)) != EOF)
{
fputc(ch, pfwrite);//把ch写入pfwrite
}
fclose(pfread);
fclose(pfwrite);
return 0;
}
输出结果:
(3)fputs
代码实现:
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
return 1;
}
//写文件 - 写一行
fputs("abcdef\n", pf);
fputs("abcdef\n", pf);
fputs("abcdef\n", pf);
fputs("abcdef\n", pf);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
(4)fgets
三个参数:
1. 输入地的指针
2.输入个数,但是要-1因为最后要输入\0
3.流
代码实现:
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
return 1;
}
//读取
char arr[20] = "xxxxxxxxxxxxxxx";
fgets(arr, 10, pf);//从流中读取9个字符(有一个放入\0)放入arr中
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
当然也可以输出到屏幕上:
看代码:
#include<stdio.h>
#include<math.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
return 1;
}
//读取
char arr[20] = "xxxxxxxxxxxxxxx";
fgets(arr, 10, stdin);//标准输入流
fputs(arr, stdout);//标准输出流
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
这里要注意的是输入流和输出流在函数的位置。
(5)fscanf和fprintf
fprintf代码实现:
#include<stdio.h>
#include<math.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = { "zhangsan", 20, 90.5f };
FILE*pf = fopen("data.txt", "w");
if (pf == NULL)
{
return 1;
}
//写文件
//printf(""%s %d %.1f", s.name, s.age, s.score");//很相似
fprintf(pf, "%s %d %.1f", s.name, s.age, s.score);
//
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
同理:fscanf
假设文件里有:
代码:
#include<stdio.h>
#include<math.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {0};
FILE* pf = fopen("data.txt", "r");//读
if (pf == NULL)
{
return 1;
}
//写读文件
fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
fprintf(stdout, "%s %d %.1f\n", s.name, s.age, s.score);//输出屏幕
//
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
6.?fwrite二进制输出
首先我们先来学习一下这个函数:
代码实现:
#include<stdio.h>
#include<math.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {"zhangsan", 20, 90.5};
FILE* pf = fopen("data.txt", "wb");//wb是以二进制的方式写入
if (pf == NULL)
{
return 1;
}
//二进制的形式写文件
fwrite(&s, sizeof(s), 1, pf);
fclose(pf);
pf = NULL;
return 0;
}
输出:
这里是以二进制输入的文本翻译成这样,是因为文本不具备二进制翻译,但是如果以二进制输出是和输入一样的结果,下面我们把刚刚以二进制输入文件以二进制输出看看。
7.fread以二进制输出
这里我们可以看到,参数和上面的fwite是一样的。
代码实现:
#include<stdio.h>
#include<math.h>
struct Stu
{
char name[20];
int age;
float score;
};
int main()
{
struct Stu s = {0};
FILE* pf = fopen("data.txt", "rb");//rb以二进制形式读进
if (pf == NULL)
{
return 1;
}
//二进制的形式du文件
fread(&s, sizeof(s), 1, pf);
printf("%s %d %lf", s.name , s.age, s.score );
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
在这里我们在认识两个函数sscanf和sprintf.
8.sscanf和sprintf.
对比:
使用:
#include <stdio.h>
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "zhangsan", 20, 85.5f };
struct S tmp = { 0 };
char arr[100] = { 0 };
sprintf(arr, "%s %d %f", s.name, s.age, s.score);//把结构体s的数据输入arr
printf("%s\n", arr);
//
sscanf(arr, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));//把arr结构体数据输入tmp
printf("%s %d %f\n", tmp.name, tmp.age, tmp.score);
return 0;
}
这里要慢慢理解,
6. ?件的随机读写
6.1 fseek和ftell
根据?件指针的位置和偏移量来定位?件指针。
什么意思,来
6.2 ftell
返回?件指针相对于起始位置的偏移量。
函数内容:
long int ftell ( FILE * stream );
现在我们来实现fseek和ftell
代码展示:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);//让光标指向d
int n = ftell(pf);//计算相对起始位置的偏移量并保存
printf("%d\n", n);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
再看看
这个:
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);//让光标指向d
int n = ftell(pf);//计算相对起始位置的偏移量并保存
printf("%d\n", n);
fseek(pf, -4, SEEK_CUR);//当前位置
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
怎么理解:
6.3 rewind
作用:让?件指针的位置回到?件的起始位置
代码展示:
#include <stdio.h>
//data.txt里面有abcdefg
int main()
{
FILE* pf = fopen("data.txt", "r");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int ch = fgetc(pf);
printf("%c\n", ch);
ch = fgetc(pf);
printf("%c\n", ch);//光标指向c
rewind(pf);//让?件指针的位置回到?件的起始位置
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
输出结果:
7. ?件读取结束的判定
7.1 被错误使?的 feof
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int c; // 注意:int,?char,要求处理EOF
FILE* fp = fopen("test.txt", "r");
if (!fp) {
perror("File opening failed");
return EXIT_FAILURE;//1
}
//fgetc 当读取失败的时候或者遇到?件结束的时候,都会返回EOF
while ((c = fgetc(fp)) != EOF) // 标准C I/O读取?件循环
{
putchar(c);
}
//判断是什么原因结束的
if (ferror(fp))//遇到错误结束
puts("I/O error when reading");
else if (feof(fp))//遇到文末结束
puts("End of file reached successfully");
fclose(fp);
}
#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
double a[SIZE] = { 1.,2.,3.,4.,5. };
FILE* fp = fopen("test.bin", "wb"); // 必须??进制模式
fwrite(a, sizeof * a, SIZE, fp); // 写 double 的数组
fclose(fp);
double b[SIZE];
fp = fopen("test.bin", "rb");
size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 读 double 的数组
if (ret_code == SIZE) {//判断返回值是否?于实际要读的个数
puts("Array read successfully, contents: ");
for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
putchar('\n');
}
else { // error handling
if (feof(fp))//yudao文末结束
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {//遇到错误结束
perror("Error reading test.bin");
}
}
fclose(fp);
}
8. ?件缓冲区
#include <stdio.h>
#include <windows.h>
//VS2019 WIN11环境测试
int main()
{
FILE* pf = fopen("test.txt", "w");
fputs("abcdef", pf);//先将代码放在输出缓冲区
printf("睡眠10秒-已经写数据了,打开test.txt?件,发现?件没有内容\n");
Sleep(10000);
printf("刷新缓冲区\n");
fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到?件(磁盘)
//注:fflush 在?版本的VS上不能使?了
printf("再睡眠10秒-此时,再次打开test.txt?件,?件有内容了\n");
Sleep(10000);
fclose(pf);
//注:fclose在关闭?件的时候,也会刷新缓冲区
pf = NULL;
return 0;
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!