【问题标题】:Read file byte by byte using C使用C逐字节读取文件
【发布时间】:2018-12-15 21:44:46
【问题描述】:

我正在尝试逐字节读取文件,然后使用 C 将其打印出来,但输出与十六进制编辑器的显示不匹配。

在十六进制编辑器中,前 2 行如下所示:

0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0111 1111 1000 0000 0000

预期输出:

00000000000000000000000000000000
00000000000001111111100000000000

但是当我的代码输出这个时:

00000000000000000000001111111100
00000000000000000000000000000000

这是我的代码:

#include <stdio.h>
#include <string.h>

int main() {
    FILE *fp;
    unsigned char buffer[4900] = "";
    int y;

    y = 0;
    fp = fopen("tugasz.ksa", "rb");

    for (int x = 0; x < 4900; x++) {
        fread(buffer, 1, 4900, fp);
        printf("%x", buffer[x]);
    }
    return (0);
}

【问题讨论】:

  • 我建议你做一些rubber duck debugging。不,您不是在“逐字节”读取文件。
  • fread 移到循环上方。设为y = fread(...),然后循环到y
  • @Weather 它给了我更多不同的输出“1ddd3cc0”
  • @Weather 等我试试
  • 您没有检查文件是否已成功打开。您没有检查来自fread() 的返回值。阅读时,您尝试一次读取 4900 个字节(而不是问题标题所暗示的逐字节读取)。您从“读取”的 4900 个值中的每个值中打印一个字节。使用getc() 一次读取一个字节。或者使用fread(),但注意返回值(它表示读取了多少字节),然后循环读取读取的值。外部循环应该调用fread() 并捕获并测试结果——size_t nbytes; while ((nbytes = fread(…)) &gt; 0)。内部循环处理nbytes 的数据。

标签: c hex byte


【解决方案1】:

您的代码中存在多个问题:

  • 您没有测试fopen 失败,如果文件不存在或无法打开,则会导致未定义的行为。
  • 您不是在逐字节读取文件,而是在读取 4900 字节的块,并且只打印每个块的一个字节。
  • 您可能很快就到达了文件末尾,但您没有测试文件末尾,因此输出可能来自文件的同一部分。一个错误隐藏另一个错误的经典案例。
  • 转换格式%x 每字节输出 1 或 2 个字符,具体取决于字节值。这是一个问题,文件内容是0x000x010x100x11,它们分别产生011011,因此输入明显未对齐。
  • 为了清洁,您应该fclose 溪流。
  • 从发布的数据来看,不清楚十六进制编辑器是以十六进制还是二进制格式显示数据,以及这些值是基于字还是基于字节。

这是一个更简单的方法:

#include <stdio.h>

int main() {
    FILE *fp;
    int c, i, max;

    fp = fopen("tugasz.ksa", "rb");
    if (fp == NULL) {
        fprintf(stderr, "cannot open input file\n");
        return 1;
    }
    for (i = 0, max = 4900; i < max && (c = getc(fp)) != EOF; i++) {
        printf("%02x", c);
        if (i % 16 == 15)
            putchar('\n');  // 16 bytes per line
        else if (i % 2 == 1)
            putchar(' ');   // group bytes in pairs
    }
    if (i % 16 != 0)
        putchar('\n');  // output a newline if needed

    fclose(fp);
    return 0;
}

【讨论】:

    【解决方案2】:
    for(int x = 0; x<4900; x++) {
       fread(buffer, 1, 4900, fp);
       printf("%x", buffer[x]);
    }
    

    在循环的第一次迭代中,这将仅打印buffer 中索引 0 处的第一个字符。

    在第二次迭代中,这将打印buffer 中索引 1 处的第二个字符。

    因此,如果您的文件小于 4900 字节,它只会打印 1 个字符。您获得更多输出的原因是当您到达文件末尾时循环不会中断。它打印的主要是垃圾,而不是实际的文件内容。

    鉴于您的输入文件的十六进制视图,以及输出全部为 0 和 1 的预期,源文件不太可能是由 0 和 1 组成的字节集合。相反,它可能包含字节从 0 到 256,每个字节是 0 和 1 位的集合。打印如下:

    int main(void)
    {
        FILE *fp = fopen("tugasz.ksa", "rb");
        if(fp)
        {
            unsigned char buffer[4096];
            size_t sz;
            int line = 0;
            while ((sz = fread(buffer, 1, sizeof(buffer), fp)) > 0)
            {
                for(int i = 0; i < sz; i++)
                {
                    //print the bits of the byte, at buffer[i]:
                    for(int j = 0; j < 8; j++)
                    {
                        int mask = 1 << (7 - j);
                        int bit = buffer[i] & mask;
                        printf("%d", bit ? 1 : 0);
                    }
    
                    //add new line for every 4 byte
                    line++;
                    if((line % 4) == 0)
                        printf("\n");
                }
            }
        }
    
        return 0;
    }
    

    如果字节为 0 和 1,则只需将其打印为 printf("%d", buffer[i])printf("%02X", buffer[i]) 以获取字节值:

    int main(void)
    {
        FILE *fp = fopen("tugasz.ksa", "rb");
        if(fp)
        {
            unsigned char buffer[4096];
            size_t sz;
            while((sz = fread(buffer, 1, sizeof(buffer), fp)) > 0)
            {
                for(int i = 0; i < sz; i++)
                    printf("%d", buffer[i]);
                    //or use "%02X" instead, for printing the byte values:
                    //printf("%02X ", buffer[i]);
            }
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 1970-01-01
      • 2012-12-01
      • 2022-01-25
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多