百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

C语言进阶教程:文件操作高级 - 二进制文件的读写

yund56 2025-05-28 23:43 21 浏览

1. 什么是二进制文件?

与文本文件不同,二进制文件存储的是原始的字节数据,而不是可读的字符。这意味着二进制文件可以存储任何类型的数据,如图像、音频、视频、程序的可执行文件、或者自定义的结构体数据等。它们不依赖于特定的字符编码(如ASCII或UTF-8),而是直接反映数据在内存中的表示。

与文本文件的区别:

  • 文本文件:以字符为单位进行读写,内容是人类可读的文本。在不同操作系统上,行尾结束符可能不同(例如,Windows使用CRLF \r\n,Linux/macOS使用LF \n)。C语言在读写文本文件时,可能会对这些行尾符进行转换。
  • 二进制文件:以字节为单位进行读写,内容是原始的二进制数据流。读写时不会进行任何转换,写入什么字节,读出来的就是什么字节。

2. 打开二进制文件

在C语言中,使用 fopen() 函数打开文件。为了以二进制模式打开文件,需要在模式字符串中包含 "b" 字符。

  • "rb": 以二进制只读方式打开文件。文件必须存在。
  • "wb": 以二进制只写方式打开文件。如果文件存在,则清空文件内容;如果文件不存在,则创建新文件。
  • "ab": 以二进制追加方式打开文件。如果文件不存在,则创建新文件。写入的数据会添加到文件末尾。
  • "rb+": 以二进制读写方式打开文件。文件必须存在。
  • "wb+": 以二进制读写方式打开文件。如果文件存在,则清空文件内容;如果文件不存在,则创建新文件。
  • "ab+": 以二进制读写追加方式打开文件。如果文件不存在,则创建新文件。读取从文件头开始,写入从文件尾开始。
 #include <stdio.h>
 
 int main() {
     FILE *fp_read, *fp_write;
 
     // 以二进制只读方式打开
     fp_read = fopen("data.bin", "rb");
     if (fp_read == NULL) {
         perror("Error opening data.bin for reading");
         return 1;
     }
     printf("File data.bin opened for binary reading.\n");
 
     // 以二进制只写方式打开
     fp_write = fopen("output.bin", "wb");
     if (fp_write == NULL) {
         perror("Error opening output.bin for writing");
         fclose(fp_read); // 关闭已打开的文件
         return 1;
     }
     printf("File output.bin opened for binary writing.\n");
 
     // ... 文件操作 ...
 
     fclose(fp_read);
     fclose(fp_write);
     printf("Files closed.\n");
 
     return 0;
 }

3. 读写二进制数据

对于二进制文件,通常使用 fread()fwrite() 函数进行读写操作。这两个函数直接操作字节块,非常适合处理结构体、数组等数据。

fwrite()函数

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

  • ptr: 指向要写入数据的内存块的指针。
  • size: 要写入的每个数据项的大小(以字节为单位)。
  • nmemb: 要写入的数据项的数量。
  • stream: 指向 FILE 对象的指针,该对象指定了输出流。

函数返回成功写入的数据项的总数。如果发生错误,返回值会小于 nmemb

fread()函数

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

  • ptr: 指向用于存储读取数据的内存块的指针。
  • size: 要读取的每个数据项的大小(以字节为单位)。
  • nmemb: 要读取的数据项的数量。
  • stream: 指向 FILE 对象的指针,该对象指定了输入流。

函数返回成功读取的数据项的总数。如果到达文件末尾或发生错误,返回值会小于 nmemb。可以使用 feof()ferror() 来区分这两种情况。

示例:读写结构体

 #include <stdio.h>
 #include <stdlib.h>
 
 // 定义一个结构体
 typedef struct {
     int id;
     char name[50];
     double score;
 } Student;
 
 int main() {
     FILE *outfile, *infile;
     Student student_out = {1, "Alice", 95.5};
     Student student_in;
 
     // 写入结构体到二进制文件
     outfile = fopen("students.dat", "wb");
     if (outfile == NULL) {
         perror("Error opening students.dat for writing");
         return 1;
     }
 
     size_t written_count = fwrite(&student_out, sizeof(Student), 1, outfile);
     if (written_count < 1) {
         perror("Error writing to students.dat");
         fclose(outfile);
         return 1;
     }
     printf("Student data written to students.dat\n");
     fclose(outfile);
 
     // 从二进制文件读取结构体
     infile = fopen("students.dat", "rb");
     if (infile == NULL) {
         perror("Error opening students.dat for reading");
         return 1;
     }
 
     size_t read_count = fread(&student_in, sizeof(Student), 1, infile);
     if (read_count < 1) {
         if (feof(infile)) {
             printf("End of file reached before reading student data.\n");
         } else if (ferror(infile)) {
             perror("Error reading from students.dat");
         }
         fclose(infile);
         return 1;
     }
 
     printf("\nStudent data read from students.dat:\n");
     printf("ID: %d\n", student_in.id);
     printf("Name: %s\n", student_in.name);
     printf("Score: %.2f\n", student_in.score);
 
     fclose(infile);
 
     return 0;
 }

示例:读写数组

 #include <stdio.h>
 
 #define ARRAY_SIZE 5
 
 int main() {
     FILE *fp;
     int numbers_out[ARRAY_SIZE] = {10, 20, 30, 40, 50};
     int numbers_in[ARRAY_SIZE];
     size_t count;
 
     // 写入整数数组到二进制文件
     fp = fopen("numbers.bin", "wb");
     if (fp == NULL) {
         perror("Error opening numbers.bin for writing");
         return 1;
     }
     count = fwrite(numbers_out, sizeof(int), ARRAY_SIZE, fp);
     if (count < ARRAY_SIZE) {
         perror("Error writing numbers to numbers.bin");
     }
     printf("%zu integers written to numbers.bin\n", count);
     fclose(fp);
 
     // 从二进制文件读取整数数组
     fp = fopen("numbers.bin", "rb");
     if (fp == NULL) {
         perror("Error opening numbers.bin for reading");
         return 1;
     }
     count = fread(numbers_in, sizeof(int), ARRAY_SIZE, fp);
     if (count < ARRAY_SIZE) {
         if (feof(fp)) {
             printf("Reached EOF before reading all numbers.\n");
         } else if (ferror(fp)) {
             perror("Error reading numbers from numbers.bin");
         }
     }
     printf("%zu integers read from numbers.bin\n", count);
     fclose(fp);
 
     printf("Numbers read: ");
     for (int i = 0; i < count; i++) {
         printf("%d ", numbers_in[i]);
     }
     printf("\n");
 
     return 0;
 }

4. 注意事项

  1. 字节序(Endianness): 当在不同体系结构(大端 vs. 小端)的机器之间交换二进制文件时,需要注意字节序问题。fwritefread 不会自动处理字节序转换。如果需要跨平台兼容性,可能需要手动进行字节序转换,或者使用标准化的数据格式(如 Protocol Buffers, JSON (文本), XML (文本))。
  2. 数据对齐(Data Alignment): 结构体在内存中的存储可能会因为数据对齐而包含填充字节。当直接将结构体写入文件并在不同编译器或平台上读取时,如果对齐方式不同,可能会导致问题。可以使用 #pragma pack (或编译器特定指令) 来控制结构体打包,但这会牺牲一些性能。
  3. 指针: 不能直接将包含指针的结构体写入二进制文件并期望在另一个程序或同一程序的不同运行实例中正确读取。指针存储的是内存地址,这些地址在不同的上下文是无效的。如果需要存储链式结构,需要将其序列化(例如,将指针转换为相对偏移量或ID,并在读取时重建链接)。
  4. 文件大小: 二进制文件可以非常大,确保有足够的磁盘空间,并在读写时进行错误检查。
  5. 错误处理: 始终检查 fopen(), fread(), fwrite() 等函数的返回值,并使用 ferror()feof() 来确定错误原因。

总结

二进制文件的读写是C语言文件操作中的重要部分,它允许程序高效地存储和检索非文本数据。通过 fopen() 以二进制模式打开文件,并使用 fread()fwrite() 进行数据块的读写,可以方便地处理各种复杂的数据结构。然而,在进行二进制I/O时,务必注意字节序、数据对齐和指针等潜在问题,以确保数据的正确性和可移植性。

相关推荐

SM小分队Girls on Top,女神战队少了f(x)?

这次由SM娱乐公司在冬季即将开演的smtown里,将公司的所有女团成员集结成了一个小分队project。第一位这是全面ACE的大姐成员权宝儿(BoA),出道二十年,在日本单人销量过千万,韩国国内200...

韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出

AmazeVR宣布将在十月份举办一场现场VR音乐会,观众将佩戴MetaQuest3进行体验。韩国女团aespa于2020年11月出道,此后在日本推出了三张金唱片,在韩国推出了...

韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend

身高163的Giselle,长腿傲人,身材比例绝了...

假唱而被骂爆的女团:IVE、NewJeans、aespa上榜

在韩国,其实K-pop偶像并不被认为是真正的歌手,因为偶像们必须兼备舞蹈能力、也经常透过对嘴来完成舞台。由于科技的日渐发达,也有许多网友会利用消音软体来验证K-pop偶像到底有没有开麦唱歌,导致假唱这...

新女团Aespa登时尚大片 四个少女四种style

来源:环球网

韩国女团aespa新歌MV曝光 画面梦幻造型超美

12月20日,韩国女团aespa翻唱曲《DreamsComeTrue》MV公开,视频中,她们的造型超美!WINTER背后长出一双梦幻般的翅膀。柳智敏笑容甜美。宁艺卓皮肤白皙。GISELLE五官精致...

女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA

女英雄萨勒芬妮(Seraphine)是拳头在2020年推出的第五位新英雄,在还没有正式上线时就备受lsp玩家的关注,因为她实在是太可爱了。和其他新英雄不同的是,萨勒芬妮在没上线时就被拳头当成虚拟偶像来...

人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?

现在的人气TOP女团是?INS粉丝数见分晓!现在爱豆和粉丝之间的交流方法变得多种多样,但是Instagram依然是主要的交流手段。很多粉丝根据粉丝数评价偶像的人气,拥有数百、数千万粉丝的组合作为全球偶...

韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞

WelcometoDrama.Pleasefollow4ruleswhilewatchingtheDrama.·1)Lookbackimmediatelywhenyoufe...

aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」

记者刘宛欣/综合报导南韩造星工厂SM娱乐曾打造出东方神起、SUPERJUNIOR、少女时代、SHINee、EXO等传奇团体,近年推出的aespa、RIIZE更是双双成为新生代一线团体,深受大众与粉丝...

南韩最活跃的女团aespa,新专辑《Girls》即将发布,盘点昔日经典

女团aespa歌曲盘点,新专辑《Girls》即将发布,期待大火。明天也就是2022年的7月8号,aespa新专辑《Girls》即将发行。这是继首张专辑《Savage》之后,时隔19个月的第二张专辑,这...

章泽天女团aespa出席戛纳晚宴 宋康昊携新片亮相

搜狐娱乐讯(山今/文玄反影/图科明/视频)法国时间5月23日晚,女团aespa、宋康昊、章泽天等明星亮相戛纳晚宴。章泽天身姿优越。章泽天肩颈线优越。章泽天双臂纤细。章泽天仪态端正。女团aespa亮...

Aespa舞台暴露身高比例,宁艺卓脸大,柳智敏有“TOP”相

作为SM公司最新女团aespa,初舞台《BlackMamba》公开,在初舞台里,看得出来SM公司是下了大功夫的,虽然之前SM公司新出的女团都有很长的先导片,但是aespa显然是有“特殊待遇”。运用了...

AESPA女团成员柳智敏karina大美女

真队内速度最快最火达成队内首个且唯一两百万点赞五代男女团中输断层第一(图转自微博)...

对来学校演出的女团成员语言性骚扰?韩国这所男高的学生恶心透了

哕了……本月4日,景福男子高中相关人士称已经找到了在SNS中上传对aespa成员进行性骚扰文章的学生,并开始着手调查。2日,SM娱乐创始人李秀满的母校——景福高中迎来了建校101周年庆典活动。当天,S...