我的代码中的fread()有什么问题?

时间:2020-08-27 08:30:34

标签: c cs50 fread

这是我现在尝试的与cs50“恢复”中以前的问题有关的代码的摘录。

我已经用fread进行了所有尝试,但是由于某种原因,它根本无法按照我想要的方式工作。

在此循环中,我试图弄清楚fread的实际工作方式。

我对fread的问题是-每次调用时,它是否一次从指向(rawdata)的文件中读取512字节的数据1?在那种情况下,我的代码应该工作,因为循环是无限期地运行,一次又一次地调用该函数,因此一次将流位置/文件游标(我不知道其叫什么)移动512字节。我在feof(rawdata)的圈里休息了。

我正在使用这个小程序来帮助我从cs50 pset4中恢复。

    // In a loop, until the end of file has been reached,
    while (true) {
        // Zeroing counter
        jpg_counter = 0;
        // Reading 512 bytes into the array of bytes
        fread(bytes, 512, 1, rawdata);
        
        // Searching the 512 bytes for JPEG signatures - bytes[3] with bitwise AND
        if (bytes[0] == 0xff && bytes[1] == 0xd8 && bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0) {
            jpg_counter++;
        }
        
        // If found JPG, add total and keep going till end of file
        if (jpg_counter != 0) {
            total++;
        }
 
        //feof returns a non zero value only at the end of a file
        if (feof(rawdata) != 0) {
            break;
        }
    }
    printf("%i\n", total);

2 个答案:

答案 0 :(得分:1)

您的方法存在两个主要问题:

  • 您没有在读取循环中正确测试文件结尾。您应该使用返回值fread来确定是否已从流中读取至少一个字节,并且应该以相反的顺序传递参数:您正在读取多达512个字节:

      size_t n;
      while ((n = fread(bytes, 1, 512, rawdata)) > 0) {
          // n bytes were read from the file.
    
  • ,您仅测试JPEG签名的前4个字节。除非已知文件具有非常特定的结构,否则您可能要在块中搜索签名。

  • 必须小心处理签名重叠的块,即:从512字节的块的末尾开始,在下一个块的末尾结束。

这是修改后的版本:

int count_jpeg(FILE *rawdata) {
    unsigned char bytes[3 + 512];
    int pos = 0, end, i;
    int total = 0;
    size_t nread;
    // In a loop, until the end of file has been reached,
    while ((nread = fread(bytes + pos, 1, 512, rawdata)) > 0) {
        end = pos + nread - 3;
        for (i = 0; i < end; i++) {
            // Searching the block for JPEG signatures - bytes[3] with bitwise AND
            if (bytes[i] == 0xff && bytes[i + 1] == 0xd8
            &&  bytes[i + 2] == 0xff && (bytes[i + 3] & 0xf0) == 0xe0) {
                total++;
                i += 3;
            }
        }
        // copy the last 3 bytes to the beginning of the block
        for (i = pos = 0; i < 3; i++)
            if (end + i >= 0) {
                bytes[pos++] = bytes[end + i];
        }
    }
    printf("%i\n", total);
    return total;
}

编辑::如果已知JPEG签名在512字节边界上对齐,则可以删除扫描循环,但是仍然可以读取文件末尾的部分块:

int count_jpeg(FILE *rawdata) {
    unsigned char bytes[512];
    int total = 0;

    // In a loop, until the end of file has been reached,
    while (fread(bytes + pos, 1, 512, rawdata) > 4) {
        /* check for a signature at the beginning of the block */
        if (bytes[0] == 0xff && bytes[1] == 0xd8
        &&  bytes[2] == 0xff && (bytes[3] & 0xf0) == 0xe0) {
            total++;
        }
    }
    printf("%i\n", total);
    return total;
}

答案 1 :(得分:0)

恐惧状态手册页

函数fread()读取nmemb数据项,每个数据项的长度为字节, 从流指向的流中,将它们存储在该位置 由ptr提供

因此您可以将读取的元素数量存储在变量中,并检查是否读取了512个字节。

int nmenb = fread(bytes, 512, 1, rawdata);

if( nmemb != 1 )
{
  //exit
}
else{
      // 512 bytes read successfully 
}