如何在C语言中读取二进制文件并模拟xxd格式输出
实现类似xxd的二进制文件十六进制输出及二进制文件读取存储
我有一个名为
add_num.mi的二进制文件,用命令xxd -c 4 add_nums.mi | head -n 9查看的内容如下:00000000: 1301 f07f .... 00000004: ef00 c000 .... 00000008: b717 0000 .... 0000000c: 2386 0780 #... 00000010: b717 0000 .... 00000014: 1307 8004 .... 00000018: 2380 e780 #... 0000001c: 1305 0000 .... 00000020: 6780 0000 g...我想用C语言实现上述格式的输出,同时想了解如何逐行读取二进制文件并存储内容。目前尝试的代码无法正常工作,代码如下:
#include <stdio.h> int main() { FILE *fp; unsigned char ch; fp = fopen("examples/add_2_numbers/add_2_numbers.mi", "rb"); if (fp == NULL) { printf("Error opening file\n"); return 1; } while ((ch = fgetc(fp)) != EOF) { // read file character by character printf("%c", ch); } fclose(fp); return 0; }
一、现有代码的问题
你的代码直接用printf("%c", ch)输出二进制字节,这会把字节当作ASCII字符打印,很多非可打印字符会显示为乱码或控制字符,自然无法得到xxd那样的十六进制格式输出。
二、实现类似xxd的十六进制输出
要实现和xxd -c 4一致的格式,需要跟踪偏移地址、按固定字节数打印十六进制内容,同时补充ASCII字符的可视化。以下是完整实现:
#include <stdio.h> #include <ctype.h> int main() { FILE *fp; unsigned char buffer[4]; size_t bytes_read; unsigned long offset = 0; fp = fopen("examples/add_2_numbers/add_2_numbers.mi", "rb"); if (fp == NULL) { printf("Error opening file\n"); return 1; } // 每次读取4个字节,直到文件结束 while ((bytes_read = fread(buffer, 1, 4, fp)) > 0) { // 打印8位十六进制偏移地址 printf("%08lx: ", offset); // 打印十六进制内容,每两个字节加空格 for (size_t i = 0; i < 4; i++) { if (i < bytes_read) { printf("%02x", buffer[i]); } else { // 文件末尾不足4字节时补空格对齐 printf(" "); } if (i == 1) { printf(" "); } } // 打印ASCII字符,不可打印字符用.代替 printf(" "); for (size_t i = 0; i < bytes_read; i++) { printf("%c", isprint(buffer[i]) ? buffer[i] : '.'); } // 不足4字节时补.对齐 for (size_t i = bytes_read; i < 4; i++) { printf("."); } printf("\n"); offset += bytes_read; } fclose(fp); return 0; }
代码说明
- 用
fread批量读取4字节,比逐个字节读取更高效 %08lx保证偏移地址始终为8位十六进制,不足补0isprint函数判断字符是否可打印,统一用.替代不可打印字符- 处理文件末尾不足4字节的情况,补空格和
.维持格式一致性
三、逐行(按块)读取二进制文件并存储
二进制文件本身没有“行”的概念,所谓的“行”是人为按固定字节数(比如4字节)划分的逻辑块。以下两种方法可实现存储:
方法1:固定大小数组存储(适合已知文件大小)
#include <stdio.h> #include <stdlib.h> #define BLOCK_SIZE 4 #define MAX_BLOCKS 100 // 根据实际文件大小调整 int main() { FILE *fp; unsigned char data[MAX_BLOCKS][BLOCK_SIZE]; size_t block_count = 0; size_t bytes_read; fp = fopen("examples/add_2_numbers/add_2_numbers.mi", "rb"); if (fp == NULL) { printf("Error opening file\n"); return 1; } // 逐块读取并存储 while (block_count < MAX_BLOCKS && (bytes_read = fread(data[block_count], 1, BLOCK_SIZE, fp)) > 0) { block_count++; } printf("共读取了%zu个块\n", block_count); // 示例:打印第一个块的十六进制内容 if (block_count > 0) { printf("第一个块内容:"); for (int i = 0; i < BLOCK_SIZE; i++) { printf("%02x ", data[0][i]); } printf("\n"); } fclose(fp); return 0; }
方法2:动态内存分配(适合未知文件大小)
#include <stdio.h> #include <stdlib.h> #define BLOCK_SIZE 4 int main() { FILE *fp; unsigned char **data = NULL; size_t block_count = 0; size_t bytes_read; fp = fopen("examples/add_2_numbers/add_2_numbers.mi", "rb"); if (fp == NULL) { printf("Error opening file\n"); return 1; } // 循环读取并动态扩展内存 while ((bytes_read = fread(buffer, 1, BLOCK_SIZE, fp)) > 0) { // 扩展存储块的指针数组 unsigned char **temp = realloc(data, (block_count + 1) * sizeof(unsigned char *)); if (temp == NULL) { printf("内存分配失败\n"); // 释放已分配的内存 for (size_t i = 0; i < block_count; i++) { free(data[i]); } free(data); fclose(fp); return 1; } data = temp; // 为当前块分配内存 data[block_count] = malloc(BLOCK_SIZE); if (data[block_count] == NULL) { // 内存分配失败,清理资源 for (size_t i = 0; i < block_count; i++) { free(data[i]); } free(data); fclose(fp); return 1; } // 复制读取的内容到当前块 for (size_t i = 0; i < bytes_read; i++) { data[block_count][i] = buffer[i]; } // 不足4字节的部分补0(可选) for (size_t i = bytes_read; i < BLOCK_SIZE; i++) { data[block_count][i] = 0; } block_count++; } printf("共读取了%zu个块\n", block_count); // 使用完毕后释放内存 for (size_t i = 0; i < block_count; i++) { free(data[i]); } free(data); fclose(fp); return 0; }
内容的提问来源于stack exchange,提问作者TheRealCoder1123
相关产品推荐
相关产品推荐

