C语言中的文件和文件操作

欢迎来到C语言的文件操作教程!在这篇文章中,我们将探讨C语言中的文件操作,包括文本文件和二进制文件的处理,文件的打开和关闭,文件的顺序读写和随机读写,以及文件读取结束的判定和文件缓冲区的使用。

一、文本文件和二进制文件

在C语言中,文件被分为两类:文本文件和二进制文件。

  • 文本文件是由字符组成的文件,可以使用文本编辑器打开并查看其内容。文本文件中的字符通常使用ASCII编码,每个字符占用一个字节。

  • 二进制文件可以包含任意类型的数据,如整数、浮点数、结构体等。二进制文件中的字节是按照原始的二进制形式存储的,通常不使用任何编码。

二、文件的打开和关闭

在C语言中,我们使用fopen函数来打开一个文件,使用fclose函数来关闭一个已打开的文件。

FILE *fp;
fp = fopen("file.txt", "r"); // 打开一个名为"file.txt"的文件进行读取
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
// 对文件进行操作
fclose(fp); // 关闭文件

三、文件的顺序读写

顺序读写是指按照文件中的数据顺序,从头到尾进行读写。在C语言中,我们可以使用fgetc, fputc, fgets, fputs, fscanf, fprintf等函数进行顺序读写。

1. 读取字符

fgetc函数用于从文件中读取一个字符。它的原型是:

int fgetc(FILE *stream);

这个函数从stream指向的文件中读取一个字符,并返回它。如果已经到达文件的末尾,或者发生了错误,它将返回EOF

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
char ch;
while ((ch = fgetc(fp)) != EOF) {
    putchar(ch);
}
fclose(fp);

2. 写入字符

fputc函数用于向文件中写入一个字符。它的原型是:

int fputc(int c, FILE *stream);

这个函数将字符c写入stream指向的文件,并返回写入的字符。如果发生了错误,它将返回EOF

FILE *fp = fopen("file.txt", "w");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
char ch = 'A';
fputc(ch, fp);
fclose(fp);

3. 读取字符串

fgets函数用于从文件中读取一个字符串。它的原型是:

char *fgets(char *str, int n, FILE *stream);

这个函数从stream指向的文件中读取最多n-1个字符,并将它们存储在str指向的字符数组中。如果遇到换行符或文件的末尾,读取将停止。

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
char str[100];
while (fgets(str, 100, fp) != NULL) {
    printf("%s", str);
}
fclose(fp);

4. 写入字符串

fputs函数用于向文件中写入一个字符串。它的原型是:

int fputs(const char *str, FILE *stream);

这个函数将str指向的字符串写入stream指向的文件。

FILE *fp = fopen("file.txt", "w");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
char *str = "Hello, World!";
fputs(str, fp);
fclose(fp);

5. 格式化读取和写入

fscanffprintf函数用于从文件中读取和写入格式化的数据。

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
int num;
fscanf(fp, "%d", &num); // 读取一个整数
fclose(fp);

fp = fopen("file.txt", "w");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
fprintf(fp, "The number is %d\n", num); // 写入一个整数
fclose(fp);

以下是一个使用C语言格式化输入和输出结构体数据的例子:

首先,我们定义一个结构体Student,包含nameagegrade三个字段。

typedef struct {
    char name[50];
    int age;
    float grade;
} Student;

然后,我们可以创建一个Student类型的变量,并从文件中读取数据填充这个变量:

FILE *fp = fopen("student.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}

Student s;
fscanf(fp, "%s %d %f", s.name, &s.age, &s.grade);

fclose(fp);

在这个例子中,我们假设student.txt文件的内容如下:

ZhangSan 20 85.5

最后,我们可以将Student类型的变量的数据写入到文件中:

FILE *fp = fopen("output.txt", "w");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}

Student s = {"LiSi", 22, 90.0};
fprintf(fp, "%s %d %.2f", s.name, s.age, s.grade);

fclose(fp);

在这个例子中,output.txt文件的内容将会是:

LiSi 22 90.00

四、文件的随机读写

随机读写是指可以在文件的任何位置开始读写。在C语言中,我们可以使用fseek, ftellrewind函数来改变文件指针的位置。

1. fseek函数

fseek函数用于在文件中移动文件指针。它的原型是:

int fseek(FILE *stream, long offset, int whence);

这个函数将stream指向的文件的文件指针移动offset个字节。whence参数决定了offset的起始位置:

  • 如果whenceSEEK_SET,那么offset是从文件的开头开始的。
  • 如果whenceSEEK_CUR,那么offset是从当前位置开始的。
  • 如果whenceSEEK_END,那么offset是从文件的末尾开始的。

如果成功,fseek函数返回0。如果发生错误,它返回非零值。

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
fseek(fp, 10, SEEK_SET); // 将文件指针移动到文件的第10个字节
fclose(fp);

2. ftell函数

ftell函数用于获取当前文件指针的位置。它的原型是:

long ftell(FILE *stream);

这个函数返回stream指向的文件的文件指针的当前位置。

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
long position = ftell(fp); // 获取当前文件指针的位置
printf("当前位置:%ld\n", position);
fclose(fp);

3. rewind函数

rewind函数用于将文件指针重置到文件的开头。它的原型是:

void rewind(FILE *stream);

这个函数将stream指向的文件的文件指针移动到文件的开头。

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
rewind(fp); // 将文件指针重置到文件的开头
fclose(fp);

使用示例:

fseek(fp, 10, SEEK_SET); // 将文件指针移动到文件的第10个字节
long position = ftell(fp); // 获取当前文件指针的位置
rewind(fp); // 将文件指针重置到文件的开头

五、文件读取结束的判定

1. 文本文件读取结束的判定

我们可以通过检查fgetcfgets函数的返回值来判断是否已经到达文件的末尾。

(1)fgetc函数

fgetc函数用于从文件中读取一个字符。如果已经到达文件的末尾,或者发生了错误,它将返回EOF

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
    putchar(ch);
}
fclose(fp);

在这个例子中,我们使用fgetc函数在读取文件的过程中判断是否已经到达文件的末尾。当fgetc函数返回EOF时,我们就知道已经读取到了文件的末尾,于是停止读取。

(2)fgets函数

fgets函数用于从文件中读取一个字符串。如果已经到达文件的末尾,或者发生了错误,它将返回NULL

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
char str[100];
while (fgets(str, 100, fp) != NULL) {
    printf("%s", str);
}
fclose(fp);

在这个例子中,我们使用fgets函数在读取文件的过程中判断是否已经到达文件的末尾。当fgets函数返回NULL时,我们就知道已经读取到了文件的末尾,于是停止读取。

2. 二进制文件读取结束的判定

二进制文件的读取结束判定与文本文件类似,也可以通过检查读取函数的返回值来进行。在C语言中,我们通常使用fread函数来读取二进制文件。

fread函数

fread函数用于从文件中读取数据。它的原型是:

size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

这个函数从stream指向的文件中读取count个数据项,每个数据项的大小为size字节,并将它们存储在ptr指向的内存区域。函数返回实际读取的数据项数量。如果这个数量小于count,那么可能已经到达了文件的末尾,或者发生了错误。

以下是一个使用fread函数的例子:

FILE *fp = fopen("file.bin", "rb");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
int buffer[100];
size_t result = fread(buffer, sizeof(int), 100, fp);
if (result < 100) {
    if (feof(fp)) {
        printf("到达文件末尾\n");
    } else {
        printf("发生错误\n");
    }
}
fclose(fp);

在这个例子中,我们使用fread函数在读取文件的过程中判断是否已经到达文件的末尾。当fread函数返回的数量小于我们期望的数量时,我们就知道可能已经读取到了文件的末尾,于是使用feof函数进行确认。

附:feof函数和ferror函数

在C语言中,feofferror函数用于检查文件读取结束时,判断读取结束的原因为遇到文件结尾结束遇到错误结束

(1)feof函数

feof函数用于检查是否是因遇到文件结尾结束。它的原型是:

int feof(FILE *stream);

这个函数如果到达了stream指向的文件的末尾,就返回非零值。如果没有到达文件的末尾,或者发生了错误,就返回零。

(2)ferror函数

ferror函数用于检查是否是因遇到错误结束。它的原型是:

int ferror(FILE *stream);

这个函数如果stream指向的文件的最后一个操作出现错误,就返回非零值。如果最后一个操作成功,就返回零。

以下是一个使用feofferror函数的例子:

FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
int ch;
while ((ch = fgetc(fp)) != EOF) {
    putchar(ch);
}
if (feof(fp)) {
    printf("到达文件末尾\n");
} else if (ferror(fp)) {
    printf("发生错误\n");
}
fclose(fp);

在这个例子中,我们使用feof函数和ferror函数判断在文件读取结束的时候是因为遇到文件结尾结束还是因为遇到错误结束

六、文件缓冲区

文件缓冲区是文件读写性能优化的一种手段。在C语言中,所有的文件操作都是通过缓冲区进行的。我们可以使用fflush函数来清空缓冲区。

fflush(fp); // 清空文件缓冲区

1. 为什么需要文件缓冲区?

文件操作是一种相对较慢的I/O操作。每次对文件进行读写操作,都需要在CPU和磁盘之间进行数据传输,这会消耗大量的时间。为了提高效率,C语言引入了文件缓冲区的概念。

当我们对文件进行读取操作时,C语言会一次性从磁盘中读取大量的数据,并将这些数据存储在文件缓冲区中。然后,我们可以直接从文件缓冲区中读取数据,而不需要每次都去访问磁盘。

同样,当我们对文件进行写入操作时,C语言会先将数据写入到文件缓冲区中,然后在合适的时机一次性将文件缓冲区中的数据写入到磁盘中。

通过这种方式,文件缓冲区可以大大减少CPU和磁盘之间的数据传输次数,从而提高文件读写的效率

2. 如何使用文件缓冲区?

在C语言中,所有的文件操作都是通过文件缓冲区进行的。我们无需手动管理文件缓冲区,C语言会自动为我们处理。

但是,有时候我们可能需要手动控制文件缓冲区。例如,当我们对文件进行写入操作后,可能需要立即将文件缓冲区中的数据写入到磁盘中。这时,我们可以使用fflush函数来清空文件缓冲区。

FILE *fp = fopen("file.txt", "w");
if (fp == NULL) {
    printf("无法打开文件\n");
    return 1;
}
fputs("Hello, World!", fp);
fflush(fp); // 将文件缓冲区中的数据写入到磁盘中
fclose(fp);

在这个例子中,fflush函数将文件缓冲区中的数据立即写入到磁盘中,而不需要等待C语言自动进行这个操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值