You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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位十六进制,不足补0
  • isprint函数判断字符是否可打印,统一用.替代不可打印字符
  • 处理文件末尾不足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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:35:29