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.
从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(),如果您将缓冲区初始化为某个其他填充值,则会看到这些字节.