fread只有.PNG文件的前5个字节

Sam*_*urn 9 c file-io stdio msvcrt fread

我已经制作了一个简单的资源包装器,用于将我的游戏资源打包到一个文件中.在我开始编写解包器之前,一切都很顺利.我注意到我已经打包的.txt文件--26个字节 - 来自资源文件,没有任何问题,保留了所有数据.但是,当读取我在资源文件中打包的.PNG文件时,前5个字节完好无损,而其余的则完全无效.

我追溯到打包过程,我注意到fread只读取.PNG文件的前5个字节,我不能为我的生活找出原因.它甚至触发'EOF'表示文件只有5个字节长,而实际上它是一个787字节的小多边形PNG,100px×100px.

我甚至通过单独的应用程序来简单地将这个PNG文件读入缓冲区来测试这个问题,我得到相同的结果,只读取5个字节.

以下是该小型独立应用程序的代码:

#include <cstdio>

int main(int argc, char** argv)
{
    char buffer[1024] = { 0 };
    FILE* f = fopen("test.png", "r");
    fread(buffer, 1, sizeof(buffer), f);
    fclose(f);        //<- I use a breakpoint here to verify the buffer contents
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

有人可以指出我的愚蠢错误吗?

Sig*_*erm 21

有人可以指出我的愚蠢错误吗?

Windows平台,我想?

用这个:

FILE* f = fopen("test.png", "rb");
Run Code Online (Sandbox Code Playgroud)

而不是这个:

FILE* f = fopen("test.png", "r");
Run Code Online (Sandbox Code Playgroud)

有关说明,请参见msdn.


RBe*_*eig 8

从SigTerm扩展正确的答案,这里有一些背景知道为什么你得到了在文本模式下打开PNG文件的效果:

PNG格式解释了其8字节文件头,如下所示:

PNG文件的前八个字节始终包含以下值:

   (decimal)              137  80  78  71  13  10  26  10
   (hexadecimal)           89  50  4e  47  0d  0a  1a  0a
   (ASCII C notation)    \211   P   N   G  \r  \n \032 \n

此签名既将文件标识为PNG文件,又可立即检测常见的文件传输问题.前两个字节区分系统上的PNG文件,这些文件期望前两个字节唯一地标识文件类型.选择第一个字节作为非ASCII值,以降低文本文件被误识别为PNG文件的可能性; 此外,它捕获了清除第7位的错误文件传输.字节2到4命名格式.CR-LF序列捕获改变换行序列的错误文件传输.control-Z字符在MS-DOS下停止文件显示.最后换行符检查CR-LF转换问题的反转.

我相信在文本模式下,fread()当它读取包含Ctrl + Z字符的第六个字节时,调用终止.Ctrl + Z历史上用于MSDOS(以及之前的CPM)以指示文件的结尾,这是必要的,因为文件系统将文件大小存储为块计数,而不是字节计数.

通过以文本模式而不是二进制模式读取文件,您触发了防止意外使用TYPE命令显示PNG文件的保护.

你可以做的一件事有助于诊断这个错误,使用方式fread()略有不同.您没有测试返回值fread().你应该.此外,您应该这样称呼它:

...
size_t nread;
...
nread = fread(buffer, sizeof(buffer), 1, f);
Run Code Online (Sandbox Code Playgroud)

nread是实际写入缓冲区的字节数.对于文本模式下的PNG文件,它会在第一次读取时告诉您它只读取5个字节.由于文件不能那么小,你可能已经知道其他事情正在发生.缓冲区的剩余字节从未被修改过fread(),如果您将缓冲区初始化为某个其他填充值,则会看到这些字节.