目录
文件
文件分两种,第一种是程序文件,后一种是数据文件。
程序文件:包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj)可执行程序(windows环境后缀为.exe)。
数据文件:文件的内同 不一定是程序,而是程序员运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出的文件。
文件名:
文件名包含三部分:文件路径+文件名主干+文件后缀
例:c:\code\test.txt
进行文件操作时需要用到流
"流"(stream)通常用于描述数据的传输或处理。流可以是输入流(input stream)或输出流(output stream),它们分别用于从外部源读取数据或将数据写入外部目标。
输入流:输入流用于从外部源(比如文件、键盘、网络等)读取数据到程序中。在C语言中,你可以使用标准输入流(stdin)来接收用户输入,也可以使用文件输入流来读取文件中的数据。
输出流:输出流用于将程序中的数据写入外部目标(比如文件、屏幕、网络等)。在C语言中,你可以使用标准输出流(stdout)来输出到屏幕上,也可以使用文件输出流将数据写入文件。
标准流
stdin-标准输入流,可以将数据写入一个文本文件,并将该文件重定向到程序的标准输入。
stdout-标准输出流,程序的输出重定向到文件或其他位置,可以使用标准输出(stdout)重定向。
stderr-标准错误流,大多数环境中输出到显示器上面。
标准流的类型是FILE*,通常称为文件指针。
文件指针
缓冲文件系统中,关键的概念是"文件类型指针"简称"文件指针"
每个被使用的文件都在内存中开辟了一个相应的**文件信息区。**这些信息保存在结构体变量中,该结构体由系统声明,取名FILE
结构体原型:
typedef struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
} FILE;
文件的读写
文件读写应先打开后关闭
ANSIC规定使用fopen函数打开文件,fclose来关闭文件。
//打开文件
FILE * fopen(const char * filename, const char * mode);
//关闭文件
int fclose(FILE * stream);
文件的使用方式
文件的顺序读写:
fgetc和fputc
fgetc
是C标准库中用于从文件中读取一个字符的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
int fgetc(FILE *stream);
stream
:指向FILE
结构体的指针,表示要读取字符的文件流。
fgetc
函数的作用是从指定的文件流中读取一个字符,并将该字符作为无符号字符返回。如果到达文件末尾或者发生错误,它会返回 EOF(End Of File)。
fputc
是C标准库中用于向文件中写入一个字符的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
int fputc(int character, FILE *stream);
character
:要写入到文件的字符。stream
:指向FILE
结构体的指针,表示要写入字符的文件流。
fputc
函数的作用是向指定的文件流中写入一个字符。它会将指定的字符写入到文件中,并返回写入的字符。如果写入成功,则返回写入的字符;如果发生错误,返回 EOF
。
fgets和fputs
fgets
是C标准库中用于从文件流中读取一行数据的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
char *fgets(char *str, int num, FILE *stream);
str
:指向一个字符数组的指针,用于存储读取的字符串数据。num
:要读取的最大字符数(包括空字符)。stream
:指向FILE
结构体的指针,表示要读取数据的文件流。
fgets
函数会从指定的文件流中读取一行数据(包括换行符),并将其存储到指定的字符数组中。它会一直读取直到遇到换行符 \n
、文件结束符 EOF
或者读取了 num-1
个字符为止,并在最后添加一个 null 字符 \0
作为字符串的结尾。
fputs
是C标准库中用于向文件中写入字符串的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
int fputs(const char *str, FILE *stream);
str
:要写入到文件的字符串。stream
:指向FILE
结构体的指针,表示要写入字符串的文件流。
fputs
函数的作用是向指定的文件流中写入一个以 null 结尾的字符串。它会将指定的字符串写入到文件中,并返回非负值(非错误);如果发生错误,返回 EOF
。
fscanf和fprintf
fscanf
是C标准库中用于从文件中读取格式化输入的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
int fscanf(FILE *stream, const char *format, ...);
stream
:指向FILE
结构体的指针,表示要读取数据的文件流。format
:格式化字符串,指定了要读取的数据类型和格式。
fscanf
函数根据指定的格式字符串从文件流中读取数据,并根据格式进行解析和存储。它将读取的数据转换为相应的数据类型,并按照格式字符串的指示将数据存储到相应的变量中。
fprintf
是C标准库中用于将格式化数据输出到文件的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
int fprintf(FILE *stream, const char *format, ...);
stream
:指向FILE
结构体的指针,表示要输出数据的文件流。format
:格式化字符串,指定了要输出的数据类型和格式。
fprintf
函数根据指定的格式字符串将数据格式化后输出到指定的文件流中。它类似于 printf
函数,但是可以将输出重定向到文件而不是标准输出。
fread和fwrite
fread
是C标准库中用于从文件中读取数据的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr
:指向存储读取数据的内存块的指针。size
:要读取的每个数据项的字节数。nmemb
:要读取的数据项的数量。stream
:指向FILE
结构体的指针,表示要读取数据的文件流。
fread
函数从文件流中读取数据,并将数据存储到指定的内存块中。它会返回实际读取的数据项数量,通常用于读取二进制数据。
fwrite
是 C 标准库中用于将数据写入文件的函数。它的原型定义在 <stdio.h>
头文件中,通常的函数原型如下:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
ptr
:指向要写入文件的数据块的指针。size
:每个数据项的大小(字节数)。nmemb
:要写入的数据项的数量。stream
:指向FILE
结构体的指针,表示要写入数据的文件流。
fwrite
函数将指定数量的数据项从内存中写入到文件中。它通常用于写入二进制数据到文件。
使用部分
文件的打开和关闭
以下是打开文件和关闭文件的操作
#include <stdio.h>
int main()
{
FILE* pf = fopen("data.txt", "w");//创建文件 打开文件
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
//....
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
这样就创建了data.txt文件
在我这里,D:\clone仓库\test.c\test_3_26表示当前目录
.表示当前目录
..表示上一目录
fputc和fgetc的使用
使用fputc写入26个小写字母
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
int i = 0;
for (i = 0; i < 26; i++)
{
fputc('a' + i, pf);
}
fclose(pf);
pf = NULL;
return 0;
}
使用fgetc读取data.txt的内容
fputc和fgetc的读写都有一个共同的特点,就是光标会随着读写依次往后跳
使用fgetc函数读取data1.txt中的内容,再使用fputc函数输出到data.txt中
这里我先创建好了data1.txt并输入了内容abcdefghi。
另外需要注意的是当data2.txt开辟失败时,进行判断后,应先关闭文件data1.txt后置空。
int main()
{
//D:\clone仓库\test.c\test_3_26表示当前目录
//.表示当前目录
//..表示上一目录
FILE* pf1 = fopen("data1.txt", "r");//创建文件 打开文件
if (pf1 == NULL)
{
perror("fopen");
return 1;
}
FILE* pf2 = fopen("data2.txt", "w");
if (pf2 == NULL)
{
fclose(pf1);
pf1 = NULL;
perror("fopen->data2.txt");
return 1;
}
//写文件
int ch = 0;
while ((ch = fgetc(pf1)) != EOF)
{
fputc(ch, pf2);
}
//关闭文件
fclose(pf1);
fclose(pf2);
pf1 = NULL;
pf2 = NULL;
return 0;
}
fgets和fputs的使用
fputs一次写入一行
int main()
{
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
fputs("abcdefg\n", pf);
fputs("abcdefg\n", pf);
fputs("abcdefg\n", pf);
fclose(pf);
pf = NULL;
return 0;
}
fgets注意有三个参数,其中的num参数是最多读取多少个的意思,最多读取num-1个字符。
第一个参数是数组第二参数是num,第三个参数是文件指针,是把文件里的字符读取到数组中
这里data.txt是一堆字母,num是10,但一共读取了9个字符。
fscanf和fprintf的使用
读取带有格式化的字符
struct stu
{
char neme[30];
int age;
double score;
};
int main()
{
struct stu s = { "zhangsan", 29, 99.5 };
FILE* pf = fopen("data.txt", "w");
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fprintf(pf, "%s %d %.1lf", s.neme, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}
注意使用fscanf和scanf一样要&(取地址)
这里创建了一个未初始化的s使用fscanf函数读取data.txt的内容读入s中,后用fprintf打印再屏幕上。
fread和fwrite的使用
二进制的读写
fwrite四个参数,第一个是要写数据的起始地址,第二个是一个元素的大小,第三个是写入的个数,第四个是流
再文件出现了乱码,这就是二进制翻译出的字符,不能识别
struct stu
{
char neme[30];
int age;
double score;
};
int main()
{
struct stu s = { "zhangsan", 19, 99.5 };
FILE* pf = fopen("data.txt", "wb");//二进制读写
if (pf == NULL)
{
perror("fopen");
return 1;
}
//写文件
fwrite(&s, sizeof(s), 1, pf);//写到pf中
fclose(pf);
pf = NULL;
return 0;
}
fread可以识别二进制的代码
struct stu
{
char neme[30];
int age;
double score;
}s;
int main()
{
//struct stu s = { "zhangsan", 19, 99.5 };
FILE* pf = fopen("data.txt", "rb");//二进制读写
if (pf == NULL)
{
perror("fopen");
return 1;
}
//fwrite(&s, sizeof(s), 1, pf);
//读文件
fread(&s, sizeof(s), 1, pf);//写到pf中
printf("%s %d %.1lf", s.neme, s.age, s.score);
fclose(pf);
pf = NULL;
return 0;
}