1.什么是文件
定义:磁盘上的文件是文件,程序设计中我们一般接触到两种文件:程序文件和数据文件
程序文件
包括源文件(后缀为.c),目标文件(windows环境下后缀为.obj,gcc环境下为.o),可执行文件(本质是机器语言二进制文件后缀为.exe)
数据文件
文件的内容不一定是程序,而是文件运行时读写的数据
2.文件名
文件路径+文件名主干+文件后缀
例如:
3.二进制和文本文件
二进制文件:文件在内存中以二进制形式不加转换的输出到外存的文件中的文件就是二进制文件
文本文件:以ASCII字符的形式存储的文件
注意:不能单纯说用二进制存储好或使用文本文件存储好,读取速度快 ,
例如存放数字10000
![](https://img-blog.csdnimg.cn/direct/d0cb17b5850c46f685b451396f64ce51.png)
4.标准输入流与标准输出流
标准输入流(stdin)和标准输出流(stdout)是计算机中常用的输入输出方式。它们是操作系统提供的默认输入输出设备,用于与用户或其他程序进行交互。
标准输入流是程序从外部获取输入数据的通道。在大多数情况下,标准输入流与键盘输入相关联,程序可以通过读取标准输入流来获取用户输入的数据。例如,在命令行界面下,我们可以通过键盘输入数据并通过标准输入流传递给程序。
标准输出流是程序向外部输出数据的通道。在大多数情况下,标准输出流与屏幕输出相关联,程序可以通过将数据写入标准输出流来显示结果或信息。例如,在命令行界面下,程序可以通过将结果写入标准输出流来显示在屏幕上。
所有输入流和所有输出流是指计算机中所有可用的输入和输出通道。除了标准输入流和标准输出流之外,还可以使用其他类型的输入输出流来实现与文件、网络、设备等的交互。这些流可以通过编程语言或操作系统提供的API进行创建和操作。
文件指针:
当我们在打开或关闭文件时需要频繁的运用文件指针,文件指针指向文件信息区中相关信息的。
通过文件指针变量能够间接找到与它相关联的文件
文件信息区:
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型由系统声明的,取名 FILE.
struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;
//打开文件
FILE * fopen (const char * filename, const char * mode);
//文件操作
…………
//关闭文件
int fclose (FILE * stream);
文档操作中的mode模式 :
例如:
在C语言文件操作中,`fopen`函数用于打开一个文件,并返回一个指向`FILE`类型的指针。其中,`mode`参数用于指定文件的打开模式。
在`mode`参数中,"w"表示以写入模式打开文件,如果文件不存在则创建新文件,如果文件已存在则清空文件内容。而"r"表示以只读模式打开文件,如果文件不存在则打开失败。
`fputs`函数用于将字符串写入文件,而`fgets`函数用于从文件中读取字符串。
这两个函数与打开模式有一定的关系。如果使用"r"模式打开文件,则只能使用`fgets`函数从文件中读取字符串,而不能使用`fputs`函数写入字符串。同样地,如果使用"w"模式打开文件,则只能使用`fputs`函数写入字符串,而不能使用`fgets`函数读取字符串。
下面是一个示例代码:```c
#include <stdio.h>
int main() {
FILE *file;
char str[100];
// 以写入模式打开文件
file = fopen("example.txt", "w");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
// 使用 fputs 函数写入字符串
fputs("Hello, World!", file);
// 关闭文件
fclose(file);
// 以只读模式打开文件
file = fopen("example.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return 1;
}
// 使用 fgets 函数读取字符串
fgets(str, sizeof(str), file);
printf("从文件中读取的字符串:%s\n", str);
// 关闭文件
fclose(file);
return 0;}
如果上述代码中的 “r”与“w”位置互换就会出现以下场景:
在上述代码中,首先以写入模式打开文件,并使用`fputs`函数将字符串写入文件。然后关闭文件。
接着以只读模式打开文件,并使用`fgets`函数从文件中读取字符串,并将其打印出来。最后关闭文件。
int main()
{//打开文件
FILE* fr = fopen("test.txt", "w");
if (fr == NULL)
{//判断文件指针是否为空
perror("fopen");
}
//文件操作
fputs("Hollow world", fr);//将“Hollow world”写入流中
//关闭文件
fclose(fr);
fr == NULL;
return 0;
}
那么如何查找“test.txt”文件来检查是否将“Hollow world”写入其中呢?
按以下步骤来:
a. 打开图中的文件夹在工程项目中查找文件
b.在工程项目中查找文件
可能是文件隐藏后缀名了
5.对比函数scanf/fscanf/sscanf printf/fprintf/sprintf
scanf、fscanf、sscanf、printf、fprintf、sprintf是C语言中用于输入输出的函数,它们之间有一些区别与联系。
1. scanf:从标准输入(键盘)读取数据,并根据格式化字符串将数据存储到指定的变量中。
2. fscanf:从文件中读取数据,并根据格式化字符串将数据存储到指定的变量中。
3. sscanf:从字符串中读取数据,并根据格式化字符串将数据存储到指定的变量中。
这三个函数的区别在于数据的来源不同,但它们的使用方式和参数都是相似的。
4. printf:向标准输出(屏幕)打印格式化的数据。
5. fprintf:向文件中打印格式化的数据。
6. sprintf:将格式化的数据存储到字符串中。
这三个函数的区别在于输出的目标不同,printf是向屏幕输出,fprintf是向文件输出,sprintf是将数据存储到字符串中。它们的使用方式和参数也是相似的。
总结一下:
- scanf、fscanf、sscanf用于输入,根据不同的数据来源进行读取。
- printf、fprintf、sprintf用于输出,根据不同的输出目标进行打印或存储。
6.文件的随机读写
a. fseek
int fseek (FILE * stream, long int offset, int origin);
// 流 偏移量 起始位置
示例:
#include<stdio.h>
int main()
{
FILE* pFile = fopen("example.txt", "w");
if (pFile == NULL)
{
perror("fopen");
}
fputs("abcdefg", pFile);
fseek(pFile, 4, SEEK_SET);
fputs("hehe", pFile);
fclose(pFile);
pFile == NULL;
return 0;
}
结果:
具体过程为:
b.ftell 返回文件指针相对于起始位置的偏移量
c.rewind 让文件指针的位置返回到文件的起始位置
#include <stdio.h>
int main() {
FILE *file;
long position;
char character;
// 打开文件
file = fopen("example.txt", "r");
// 获取当前位置
position = ftell(file);
printf("当前位置:%ld\n", position);
// 读取一个字符
character = fgetc(file);
printf("读取的字符:%c\n", character);
// 获取当前位置
position = ftell(file);
printf("当前位置:%ld\n", position);
// 重新定位到文件开头
rewind(file);
// 获取当前位置
position = ftell(file);
printf("当前位置:%ld\n", position);
// 关闭文件
fclose(file);
return 0;
}
在上面的示例中,我们打开了一个名为example.txt的文件,并使用ftell函数获取了当前文件指针的位置。然后我们使用fgetc函数读取了文件中的一个字符,并再次使用ftell函数获取了当前文件指针的位置。接下来,我们使用rewind函数将文件指针重新定位到文件开头,并再次使用ftell函数获取了当前文件指针的位置。最后,我们关闭了文件。
这里的应用场景是在读取文件时,可以使用ftell函数获取文件指针的位置,以便于后续操作。比如,我们可以通过ftell函数获取当前读取位置,然后再次读取文件时可以通过rewind函数将文件指针重新定位到上一次读取的位置。这在需要多次读取或处理文件内容时非常有用
7.文件读取结束的判定
1.feof的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。
注意:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。
1. 文本文件读取是否结束,判断返回值是否为EOF ( fgetc ),或者NULL ( fgets )
例如:
• fgetc 判断是否为EOF .
• fgets 判断返回值是否为NULL .
2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
• fread判断返回值是否小于实际要读的个数。
文本文件例子:
#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;
}
//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))
printf("Error reading test.bin: unexpected end of file\n");
else if (ferror(fp)) {
perror("Error reading test.bin");
}
}
fclose(fp);
8.文件缓冲区
文件缓冲区是计算机系统中用于临时存储文件数据的一块内存区域。当我们进行文件读写操作时,数据通常不会直接写入或读取到磁盘上,而是先暂时存储在文件缓冲区中,然后再由操作系统将数据写入磁盘或从磁盘读取到缓冲区。
文件缓冲区的存在有以下几个主要目的:
1. 提高性能:将数据暂时存储在内存中可以大大提高文件读写的速度,因为内存的访问速度比磁盘快得多。
2. 减少磁盘访问次数:通过将多个小的写操作合并成一个大的写操作,可以减少对磁盘的频繁访问,提高效率。
3. 提供灵活性:文件缓冲区可以提供一些额外的功能,如缓冲区大小的设置、缓冲区刷新等,使得文件读写更加灵活和方便。
在文件缓冲区中,数据可以按照不同的模式进行读写,包括全缓冲、行缓冲和无缓冲。全缓冲表示当缓冲区满时才进行实际的读写操作;行缓冲表示当遇到换行符时才进行实际的读写操作;无缓冲表示每次读写都直接操作磁盘。
总结一下,文件缓冲区是计算机系统中用于临时存储文件数据的内存区域,它可以提高文件读写的性能和效率,并提供一些额外的功能。