重生之我在异世界学编程之C语言:深入文件操作篇(下)

大家好,这里是小编的博客频道

小编的博客:
很高兴在CSDN这个大家庭与大家相识,希望能在这里与大家共同进步,共同收获更好的自己!!!

本文目录

引言

在C语言中,文件操作是一个非常重要的部分。通过文件操作,我们可以将数据保存到磁盘上或从磁盘中读取数据。本文将详细介绍C语言的文件操作,包括顺序读写和随机读写,并重点讨论如何进行读取错误检查。每个部分都会提供多个代码例子进行阐述。那就一起来看看吧!!!


那接下来就让我们开始遨游在知识的海洋!

正文


一、文件的基本操作

(1)打开文件

使用fopen函数可以打开一个文件。函数的原型如下:

FILE *fopen(const char *filename, const char *mode);

其中,filename是文件名(包含路径),mode是文件的打开模式(如读、写等)。

常见的模式有:

"r" : 只读方式打开文件,该文件必须存在。
"w" : 写入方式打开文件,若文件存在则长度被截为0,即该文件内容会消失;若文件不存在则创建新文件。
"a" : 以附加的方式打开文件,写入的数据会被添加到文件尾,即使使用了 fseek 之类的函数也不会改变。
"r+" : 可读写的方式打开文件,该文件必须存在。
"w+" : 可读写方式打开文件,若文件存在则文件长度被截为0,即该文件内容会消失;若文件不存在则创建新文件。
"a+" : 以可读写的方式打开文件,写入的数据会被添加到文件尾。

(2)关闭文件

使用 fclose 函数可以关闭一个已打开的文件。函数的原型如下:

int fclose(FILE *stream);

(3)检测文件末尾和错误

feof(FILE *stream): 检测是否到达文件末尾

ferror(FILE *stream): 检测是否发生读写错误

(4)清除文件错误标志

使用 clearerr 函数可以清除文件错误标志和文件结束标志。函数的原型如下:

void clearerr(FILE *stream);


顺序读写是指按照文件中数据的存储顺序依次进行读写操作

二、顺序读写文件

在C语言中,文件的顺序读写涉及多个函数,这些函数允许我们按照文件中的存储顺序来读取或写入数据。以下是顺序读写相关的函数详细介绍及代码示例:

(1)字符级操作函数
fgetc()

功能:

  • 从指定的文件流中读取下一个字符(一个无符号字符),并将其作为int类型的值返回。如果到达文件末尾(EOF)或发生错误,则返回EOF

原型: int fgetc(FILE *stream);

示例:

复制代码
#include <stdio.h>
int main() {
   FILE *pf = fopen("text.txt", "r"); // 打开已经创建好的文件
   if (pf == NULL) {
       perror("fopen");
       return 1;
   }
   // 读文件
   int ret = fgetc(pf);
   printf("%c


", ret);
ret = fgetc(pf);
printf("%c
", ret);
ret = fgetc(pf);
printf("%c
", ret);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}

fputc()

功能:

  • 将一个字符写入到指定的文件流中。

原型:int fputc(int character, FILE *stream);

示例:

复制代码
#include <stdio.h>
int main() {
    FILE *pf = fopen("text.txt", "w"); // 以写模式打开文件
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    // 写文件
    fputc('a', pf);
    fputc('b', pf);
    fputc('c', pf);
    // 关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}
(2)字符串级操作函数
fgets()

功能:

  • 从指定的文件流中读取一行文本(包括换行符,如果有的话,但最多读取到数组大小减一的位置),并将其存储在字符串中。如果成功,它会返回一个指向该字符串的指针;如果发生错误或到达文件末尾(EOF)而没有读取任何字符,则返回NULL

原型: char *fgets(char *string, int n, FILE *stream);

示例:

复制代码
#include <stdio.h>
int main() {
    char arr[10] = {0};
    FILE *pf = fopen("text.txt", "r"); // 以读模式打开文件
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    // 读文件
    fgets(arr, sizeof(arr), pf);
    printf("%s
 

", arr);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}

fputs()

功能:

  • 将字符串写入到指定的文件流中,但不包括空字符''。如果成功,它返回非负值;如果发生错误,则返回EOF。

原型: int fputs(const char *string, FILE *stream);

示例:

复制代码
#include <stdio.h>
int main() {
    FILE *pf = fopen("text.txt", "w"); // 以写模式打开文件
    if (pf == NULL) {
        perror("fopen");
        return 1;
    }
    // 写文件
    fputs("Hello, World!
 

", pf);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}

(3)格式化输入输出函数
fprintf()

功能:

  • 向指定的输出流(如文件)写入格式化的数据。

原型: int fprintf(FILE *stream, const char *format[, argument]...);

示例:

复制代码
#include <stdio.h>
struct S {
   char arr[10];
   int num;
   float sc;
};
int main() {
   struct S s = {"abcde", 10, 5.5f};
   FILE *pf = fopen("text.txt", "w"); // 以写模式打开文件
   if (pf == NULL) {
       perror("fopen");
       return 1;
   }
   // 写文件
   fprintf(pf, "%s %d %f", s.arr, s.num, s.sc);
   // 关闭文件
   fclose(pf);
   pf = NULL;
   return 0;
}
fscanf()

功能:

  • 从指定的输入流(如文件)中按照指定格式读取数据。

原型: int fscanf(FILE *stream, const char *format[, argument]...);

示例:

复制代码
#include <stdio.h>
struct S {
   char arr[10];
   int num;
   float sc;
};
int main() {
   struct S s = {0};
   FILE *pf = fopen("text.txt", "r"); // 以读模式打开文件
   if (pf == NULL) {
       perror("fopen");
       return 1;
   }
   // 读文件
   fscanf(pf, "%s %d %f", s.arr, &(s.num), &(s.sc));
   // 打印
   printf("%s %d %f


", s.arr, s.num, s.sc);
// 关闭文件
fclose(pf);
pf = NULL;
return 0;
}

在C语言中,文件的随机读写是指能够在文件的任意位置进行读取或写入数据,而不仅仅是顺序地从头到尾处理文件。这种能力在处理大型数据文件时尤为重要,因为它允许程序高效地访问和修改文件中的特定部分。

三、随机读写文件

(1)文件指针与定位函数

要实现文件的随机读写,首先需要了解几个关键概念:

  1. 文件指针:用于标识打开的文件及其在存储设备上的当前位置。

  2. 定位函数 :如fseek()ftell()rewind()等,用于移动文件指针到指定位置或获取当前位置。

  • fseek(FILE *stream, long offset, int whence):将文件指针移动到相对于某个位置的偏移量处。

  • whence可以是SEEK_SET(文件开头)、SEEK_CUR(当前位置)或SEEK_END(文件末尾)。

  • ftell(FILE *stream):返回当前文件指针的位置(相对于文件开头的字节数)。

  • rewind(FILE *stream):将文件指针重新定位到文件的开头。

示例代码

以下是一些具体的例子,展示了如何在C语言中进行文件的随机读写操作。

示例1:基本随机读写
复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *file = fopen("example.txt", "w+");
    if (!file) {
        perror("Failed to open file");
        return EXIT_FAILURE;
    }

    // 写入一些初始数据
    fprintf(file, "Hello, World!
This is a test.
");

    // 移动到文件的第7个字节处(索引从0开始)
    fseek(file, 6, SEEK_SET);
    // 在此处写入新字符
    fputc('C', file);

    // 重置文件指针到文件开头
    rewind(file);

    // 读取并打印文件内容
    char buffer[100];
    while (fgets(buffer, sizeof(buffer), file)) {
        printf("%s", buffer);
    }

    fclose(file);
    return EXIT_SUCCESS;
}

在这个例子中,我们打开了一个名为example.txt的文件,写入了初始数据,然后将文件指针移动到第7个字节处(即'H''e'之间),并将该位置的字符替换为'C'。最后,重置文件指针并打印整个文件的内容。

示例2:使用ftell获取当前位置
复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *file = fopen("numbers.txt", "w+");
    if (!file) {
        perror("Failed to open file");
        return EXIT_FAILURE;
    }

    // 写入一系列数字
    for (int i = 0; i < 10; ++i) {
        fprintf(file, "%d
", i);
    }

    // 移动到文件的第5行(实际上是第4个换行符之后)
    fseek(file, 4 * (sizeof(int) + 1), SEEK_SET); // 假设每个数字和换行符占用固定大小的空间

    // 获取当前文件指针位置
    long position = ftell(file);
    printf("Current file pointer position: %ld
", position);

    // 从当前位置继续写入
    fprintf(file, "Inserted Number
");

    // 重置文件指针并打印文件内容
    rewind(file);
    char buffer[100];
    while (fgets(buffer, sizeof(buffer), file)) {
        printf("%s", buffer);
    }

    fclose(file);
    return EXIT_SUCCESS;
}

这个例子中,我们创建了一个包含数字的文件,然后尝试在第5行的位置插入一个新字符串。注意,这里对文件指针的移动是基于假设的固定大小的数字和换行符,实际应用中可能需要更精确的计算或使用其他方法来确定正确的偏移量。

示例3:二进制文件的随机读写
复制代码
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int id;
    float value;
} Record;

int main() {
    FILE *file = fopen("records.bin", "wb+");
    if (!file) {
        perror("Failed to open file");
        return EXIT_FAILURE;
    }

    // 写入一些记录
    Record records[] = {{1, 1.1}, {2, 2.2}, {3, 3.3}};
    fwrite(records, sizeof(Record), 3, file);

    // 移动到第二条记录的位置(索引从0开始)
    fseek(file, sizeof(Record), SEEK_SET);

    // 读取并修改第二条记录
    Record temp;
    fread(&temp, sizeof(Record), 1, file);
    temp.value += 10.0;

    // 将修改后的记录写回原位置(覆盖旧记录)
    fseek(file, -sizeof(Record), SEEK_CUR); // 或者直接使用之前的ftell结果
    fwrite(&temp, sizeof(Record), 1, file);

    // 重置文件指针并验证内容(这里仅为了演示,实际应关闭文件后重新打开读取)
    rewind(file);
    Record readRecords[3];
    fread(readRecords, sizeof(Record), 3, file);

    for (int i = 0; i < 3; ++i) {
        printf("ID: %d, Value: %.2f
", readRecords[i].id, readRecords[i].value);
    }

    fclose(file);
    return EXIT_SUCCESS;
}
  • 在这个例子中,我们处理一个二进制文件,其中存储了结构体数组。我们展示了如何移动到特定的记录位置,读取它,进行修改,然后再将其写回到文件中。注意,由于我们在同一文件流中进行了读取和写入操作而没有关闭再重新打开文件,这里的验证步骤在实际应用中可能不准确;通常,你应该在修改完文件后关闭它,并在需要时以只读模式重新打开它以验证更改。

在C语言中,对文件进行读写操作时,进行错误检查是至关重要的。这不仅可以确保数据的完整性,还能提高程序的健壮性和可靠性。本文将详细介绍C语言文件操作中如何进行读取错误检查,并通过多个例子加以说明。

四、读取错误检查

(1)错误检查函数

C语言提供了几个函数来检查文件操作的错误状态:

  1. ferror :用于检查文件流上的最后一个I/O操作是否出错。其原型为int ferror(FILE *stream);。如果返回非零值,则表示发生了错误。
  2. perror :用于打印描述最近一次错误的字符串。其原型为void perror(const char *s);。其中,s是一个用户提供的错误信息前缀,通常用于指示发生错误的上下文。
  3. feof :用于检查是否已经到达文件末尾。其原型为int feof(FILE *stream);。如果返回非零值,则表示已经到达文件末尾。
(2)错误处理策略

在进行文件操作时,应该遵循以下错误处理策略:

  1. 在每次调用文件操作函数后,立即检查其返回值或错误状态。
  2. 如果发现错误,根据具体情况采取适当的措施,如打印错误信息、清理资源并退出程序等。
  3. 使用clearerr函数清除文件流的错误标志和文件结束标志,以便进行下一轮的文件操作。
(3)示例代码

以下是几个使用上述函数进行文件读取错误检查的示例代码:

示例1:使用ferror检查读取错误
复制代码
#include <stdio.h>

int main() {
    FILE *fp = fopen("sample.txt", "r");
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }

    char buffer[100];
    size_t bytesRead = fread(buffer, sizeof(char), sizeof(buffer) - 1, fp);
    if (ferror(fp)) {
        perror("Error reading file");
        fclose(fp);
        return 1;
    }

    // 确保缓冲区以null字符结尾
    buffer[bytesRead] = '';
    printf("Read from file: %s
", buffer);

    fclose(fp);
    return 0;
}

在这个例子中,我们尝试从一个名为sample.txt的文件中读取数据。如果在读取过程中发生错误,我们使用ferror函数进行检查,并使用perror函数打印错误信息。

示例2:使用feof检查文件末尾
复制代码
#include <stdio.h>

int main() {
    FILE *fp = fopen("numbers.txt", "r");
    if (fp == NULL) {
        perror("Failed to open file");
        return 1;
    }

    int number;
    while (!feof(fp)) {
        if (fscanf(fp, "%d", &number) != 1) {
            // 检查是否是因为到达文件末尾而失败
            if (!feof(fp) && ferror(fp)) {
                perror("Error reading number from file");
                fclose(fp);
                return 1;
            }
            // 如果是文件末尾,则跳出循环
            break;
        }
        printf("Read number: %d
", number);
    }

    fclose(fp);
    return 0;
}

在这个例子中,我们尝试从一个名为numbers.txt的文件中读取整数。我们使用feof函数来检查是否已经到达文件末尾,同时使用ferror函数来检查是否发生了其他读取错误。


五、总结

顺序读写:按照文件中数据的存储顺序依次进行读写操作,常用函数有 fprintf , fscanf , fgets , fputs等。
随机读写:可以在文件中的任意位置进行读写操作,常用函数有fseek , ftell , rewind
错误检查:在进行文件操作时,应始终检查返回值并使用 feofferror 来检测是否到达文件末尾或发生错误。


快乐的时光总是短暂,咱们下篇博文再见啦!!!不要忘了,给小编点点赞和收藏支持一下,在此非常感谢!!!

相关推荐
阿巴斯甜5 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker5 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95276 小时前
Andorid Google 登录接入文档
android
黄林晴7 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab20 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android