C 当到达文件末尾时,fread如何处理尾随垃圾?

C 当到达文件末尾时,fread如何处理尾随垃圾?,c,fread,C,Fread,我最近又开始涉足C语言,这是一种我不是特别精通的语言,事实上,我一直在忘记(我主要用Python编写代码)。我的想法是从一个假设的大文件中读取数据作为块,然后相应地处理数据。现在,我通过将整个文件加载到带有fread的short类型的缓冲区来模拟这个过程。这种方法将会改变,因为我认为,对于一个1GB的文件来说,这是一个非常糟糕的主意。最终目标是将一个块作为一个块读取、处理、移动光标、读取另一个块,等等 这个文件有43个字节,上面有短语“敏捷的棕色狐狸跳过了懒狗”。这个大小很方便,因为它是一个素数

我最近又开始涉足C语言,这是一种我不是特别精通的语言,事实上,我一直在忘记(我主要用Python编写代码)。我的想法是从一个假设的大文件中读取数据作为块,然后相应地处理数据。现在,我通过将整个文件加载到带有fread的short类型的缓冲区来模拟这个过程。这种方法将会改变,因为我认为,对于一个1GB的文件来说,这是一个非常糟糕的主意。最终目标是将一个块作为一个块读取、处理、移动光标、读取另一个块,等等

这个文件有43个字节,上面有短语“敏捷的棕色狐狸跳过了懒狗”。这个大小很方便,因为它是一个素数,所以无论我把它分成多少字节,都会有尾随垃圾(因为缓冲区有剩余空间?)。在这种情况下,数据处理只是在字节操作后将短字符打印为两个字符(参见下面的代码)

#包括
#包括
#定义最大BUFF大小1024
长文件大小(文件*f)
{
如果(fseek(f,0,SEEK_END)!=0)退出(exit_FAILURE);//将光标移到末尾
long file_size=ftell(f);//确定获取文件大小的位置
倒带(f);
返回文件大小;
}
int main(int argc,char*argv[])
{
short buff[MAX\u buff\u SIZE]={0};//初始化为0删除尾部垃圾
char*filename=argv[1];
FILE*fp=fopen(文件名,“r”);
if(fp)
{
size_t size=sizeof(buff[0]);//每个块的大小(以字节为单位)。固定为2字节
int nmemb=(文件大小(fp)+size-1)/size;//要从文件中读取的块数
//(天花板f_尺寸/尺寸)
printf(“最多应读取%d个块”,nmemb);
short mask=0xFF;//获取第一个或第二个字节的掩码
size\u t num\u read=fread(buff,size,nmemb,fp);
printf(“读取%lu块\n\n”,num_Read);//似乎读了更多?查看。
对于(int i=0;i>8)&mask;//标识2个字节。保留掩码以保持一致性
printf(“块%02d:0x%04x |%c%c\n”,//记住小尾端(字节颠倒)
i、 buff[i],第一个字节,第二个字节);
}
fclose(fp);
}否则
{
printf(“未找到文件%s\n”,文件名);
返回1;
}
返回0;
}
昨天,在打印最后一块数据时,我得到了“chunk 21:0xffff9567 | g”。最后一个(第一个?)字节(0x67)是g,我确实希望有一些尾随垃圾,但我不明白为什么当变量buff中有短路时,它会打印出这么多字节。当时我只是将十六进制打印为%x,而不是%04x,buff没有初始化为0。今天,我决定将其初始化为0,不仅垃圾消失了,而且即使在再次取消初始化buff后,我也无法重新创建问题

下面是我希望不要太抽象的问题:

  • fread在读取数据时是否会查看文件之外的内容,是否会自行删除尾部垃圾,还是由我们决定
  • 为什么printf在缓冲区短时显示int?(我假设%x代表整数)为什么即使在没有初始化的情况下离开buff后也不能复制该行为
  • 我是否应该始终将缓冲区初始化为零以删除尾部垃圾?通常的做法是什么
  • 我希望这些问题不要太多,或者太模糊,而且我已经足够清楚了。正如我所说,我对C不太了解,但发现中低级编程非常有趣,特别是在直接数据位/字节操作方面

    希望你有一个伟大的一天

    编辑1: 你们中的一些人明智地建议我在循环中使用num\u read而不是nmemb,因为这是fread的返回值,但这意味着我将丢弃文件的其余部分(nmemb为22,而num\u read为21)。这是通常的做法吗?另外,感谢您指出%x正在转换为无符号整数,因此是4字节而不是2字节

    编辑2:
    为了澄清这一点,由于我在注释中读错了位置,我希望保留剩余的字节(或数据),而丢弃其余的未定义的字节(或数据)。我不知道这是否是通常的方法,因为如果我在循环中使用num\u read,那么不管最后剩下的是什么,不管是不是数据,都会被丢弃。我更感兴趣的是知道通常的方法是什么:丢弃剩余数据或删除我们知道的未定义的任何内容,在本例中是一个字节。

    您希望如何处理最后剩余的字节?在我看来,您的循环应该基于
    num_read
    ,因为%x取一个无符号int,所以它将通过符号扩展将你的签名短转换为int,这意味着符号位(最有效位)将被用来填充空白空间。因为您的short是0x9567,所以设置了符号位,这意味着空空间将被1s填充,从而导致0xffff9567。如果使用无符号的短字符,您将看不到0xffff。@MikeCAT只能放弃,因为它们不是来自文件本身的数据。只要我将数组初始化为零,C似乎可以帮我做到这一点,这就是为什么我假设垃圾来自统一化的缓冲区而不是fread,但我不确定,因为我不知道fread本身是如何工作的
    fread()
    的行为如文档所述。否则,许多人会抱怨过去40年。您想如何处理最后的剩余字节?在我看来,您的循环应该基于
    num_read
    ,而不是
    nmemb
    。由于%x接受一个无符号int,它将通过符号扩展将您的有符号short转换为int,这意味着符号位(最高有效位)
    #include <stdio.h>
    #include <stdlib.h>
    
    #define MAX_BUFF_SIZE 1024
    
    long file_size(FILE *f) 
    {
        if (fseek(f, 0, SEEK_END) != 0) exit(EXIT_FAILURE);     // Move cursor to the end
        long file_size = ftell(f);                              // Determine position to get file size
        rewind(f);
    
        return file_size;
    }
    
    int main(int argc, char* argv[])
    {
        short buff[MAX_BUFF_SIZE] = {0};                        // Initialize to 0 remove trailing garbage
        char* filename  = argv[1];
        FILE* fp = fopen(filename, "r");
    
        if (fp) 
        {
            size_t size = sizeof(buff[0]);                      // Size in bytes of each chunk. Fixed to 2 bytes
            int nmemb = (file_size(fp) + size - 1) / size;      // Number of chunks to read from file
                                                                // (ceil f_size/size)
            printf("Should read at most %d chunks\n", nmemb);           
    
            short mask = 0xFF;                                  // Mask to take first or second byte
    
            size_t num_read = fread(buff, size, nmemb, fp); 
    
            printf("Read %lu chunks\n\n", num_read);            // Seems to have read more? Look into.
    
            for (int i=0; i<nmemb; i++) {
                char first_byte = buff[i] & mask;
                char second_byte = (buff[i] >> 8) & mask;       // Identity for 2 bytes. Keep mask for consistency
    
                printf("Chunk %02d: 0x%04x | %c %c\n",          // Remember little endian (bytes reversed) 
                        i, buff[i], first_byte, second_byte);         
            }
            fclose(fp);
        } else 
        {
            printf("File %s not found\n", filename);
            return 1;
        }
        return 0;
    }