fread 仅 .PNG 文件的前 5 个字节

发布于 2024-09-15 03:30:17 字数 715 浏览 3 评论 0原文

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

我将其追溯到打包过程,我注意到 fread 仅读取 .PNG 文件的前 5 个字节,而我一生都无法弄清楚原因。它甚至触发“EOF”,表明该文件只有 5 个字节长,而实际上它是一个 787 字节的 PNG 小多边形,100 像素 x 100 像素。

我什至通过创建一个单独的应用程序来简单地将这个 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;
}

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

I've made a simple resource packer for packing the resources for my game into one file. Everything was going fine until I began writing the unpacker.
I noticed the .txt file - 26 bytes - that I had packed, came out of the resource file fine, without anyway issues, all data preserved.
However when reading the .PNG file I had packed in the resource file, the first 5 bytes were intact while the rest was completely nullified.

I traced this down to the packing process, and I noticed that fread is only reading the first 5 bytes of the .PNG file and I can't for the life of me figure out why. It even triggers 'EOF' indicating that the file is only 5 bytes long, when in fact it is a 787 byte PNG of a small polygon, 100px by 100px.

I even tested this problem by making a separate application to simply read this PNG file into a buffer, I get the same results and only 5-bytes are read.

Here is the code of that small separate application:

#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;
}

Can somebody please point out my stupid mistake?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

×眷恋的温暖 2024-09-22 03:30:17

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

Windows平台,我猜?

使用此:

FILE* f = fopen("test.png", "rb");

而不是此:

FILE* f = fopen("test.png", "r");

请参阅 msdn 了解解释。

Can somebody please point out my stupid mistake?

Windows platform, I guess?

Use this:

FILE* f = fopen("test.png", "rb");

instead of this:

FILE* f = fopen("test.png", "r");

See msdn for explanation.

Bonjour°[大白 2024-09-22 03:30:17

扩展来自 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);

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

Extending the correct answer from SigTerm, here is some background of why you got the effect you did for opening a PNG file in text mode:

The PNG format explains its 8-byte file header as follows:

The first eight bytes of a PNG file always contain the following values:

   (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

This signature both identifies the file as a PNG file and provides for immediate detection of common file-transfer problems. The first two bytes distinguish PNG files on systems that expect the first two bytes to identify the file type uniquely. The first byte is chosen as a non-ASCII value to reduce the probability that a text file may be misrecognized as a PNG file; also, it catches bad file transfers that clear bit 7. Bytes two through four name the format. The CR-LF sequence catches bad file transfers that alter newline sequences. The control-Z character stops file display under MS-DOS. The final line feed checks for the inverse of the CR-LF translation problem.

I believe that in text mode, the call to fread() was terminated when it read the sixth byte which contains a Ctrl+Z character. Ctrl+Z was historically used in MSDOS (and in CPM before it) to indicate the end of a file, which was necessary because the file system stored the size of a file as a count of blocks, not a count of bytes.

By reading the file in text mode instead of binary mode, you triggered the protection against accidentally using the TYPE command to display a PNG file.

One thing you could do that would have helped diagnose this error is to use fread() slightly differently. You didn't test the return value from fread(). You should. Further, you should call it like this:

...
size_t nread;
...
nread = fread(buffer, sizeof(buffer), 1, f);

so that nread is a count of the bytes actually written to the buffer. For the PNG file in text mode, it would have told you on the first read that it only read 5 bytes. Since the file cannot be that small, you would have had a clue that something else was going on. The remaining bytes of the buffer were never modified by fread(), which would have been seen if you initialized the buffer to some other fill value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文