使用 fread() 读取 BMP 的文件头

Posted

技术标签:

【中文标题】使用 fread() 读取 BMP 的文件头【英文标题】:Reading Fileheader of a BMP with fread() 【发布时间】:2014-10-24 11:44:54 【问题描述】:

我正在使用 Linux 尝试加载 BMP 的标头。我已经查看了标题,应该得到文件前两个字符的“BM”。我一直在使用的代码:

FILE* fp = fopen(filename, "r");
if(!fp)

    std::cout << "Unable to open file : " << filename << std::endl;
    return NULL;


char* headerField = new char[2];
fread(headerField, 2, sizeof(char), fp);
std::cout << headerField << std::endl;

if(strcmp(headerField, "BM"))
    delete [] headerField;
    std::cout << "File is not a bitmap" << std::endl;
    fclose(fp);
    return NULL;

else
    std::cout << "Well done!" << std::endl;

我得到的输出是 BM 后跟一个随机的额外字符,“BM7”、“BMF”、“BM*”...据我了解,fread() 应该读入(在这种情况下)两个个字符的数据,那么这个额外的字符是从哪里来的?

【问题讨论】:

headerfield 的内容没有被明确地以 null 结尾。 不需要动态分配这两个字符。为什么在 C++ 中使用旧的 C I/O 函数? “旧”C stdio 函数没有任何“错误”。只需正确使用它们和其他语言即可。许多 C++ 程序员完全跳过了 iostream,仍然使用备用 IO 库。 @codenheim 也许使用它并没有错(IMO 值得商榷),但有多种 I/O 风格。还有char* 字符串,它们不是I/O 的一部分,可以避免。人们可以构造一个论点,如果只有 c++ 特定的东西是cout,那么使用 c++ 是没有意义的。对于给定的示例,它同样有效。 如果使用原始缓冲区,stdio 可能是最合适的。他的错误不是 IO 问题。 iostream 中明确支持与 stdio 同步。 【参考方案1】:

你在大量混合 c 和 c++,我认为这是你一开始就陷入错误的一半原因。

现在,在c 中,出于某种原因,字符串被称为以空字符结尾的字符串。空字符\0 是字符串分隔符的结尾。您正在做的是将两个字节读入headerField。所以在内存中它看起来像:

|乙|中号 |垃圾|垃圾|垃圾 |

str 家族和其他例程期望char* 字符串以\0 结尾。所以strcmp 和打印在M 之后并没有停止,而是跑到了野外。一个适当的 2 字符 c 样式字符串应该占用 3 个字节,如下所示:

|乙|中号 | 0 |垃圾|垃圾 |

你如何做到这一点我留给你。

我会亲自将代码重写为适当的 c++。

【讨论】:

嗯,有一个问题,有一个解释,一个答案就是一个答案,不管我自己的喜好。我不是做代码审查的人=)。 谢谢,用流重新编写,一切似乎都很好,使用 ifstream::get 的方式几乎相同,它会自动附加一个空终止符。我正在使用上面的代码学习教程,他们完全没有使用这种方法的问题。只是出于好奇,有人知道为什么会这样吗?我能发现我们之间的唯一区别是他使用的是 mac,而我使用的是 Linux,这会影响结果吗? @JamesHodgson 如果一个人得到(不)幸运| garbage | garbage | garbage | 也可能是|0|0|0|。所以它可以按预期工作。无法保证您在未分配的内存空间中从系统获得什么。至少从标准的角度来看不是。有些系统会将所有内存归零,因此您无法在上一个进程之后恶意读取它。【参考方案2】:

“额外的垃圾”已经存在于内存中。

fread() 完全按照你说的做。它读取 2 个字符。 C 和 C++ 使用以空字符结尾的字符字符串。 cout 将打印缓冲区中的任何内容,直到到达空终止符为止。

你应该创建一个长度大于 2 的字符串,并且你应该设置一个空字符。

【讨论】:

以上是关于使用 fread() 读取 BMP 的文件头的主要内容,如果未能解决你的问题,请参考以下文章

go 读取BMP文件头

用标准c读取bmp文件的长宽?

Fread 返回 0,从 BMP 文件中读取像素

Bmp图像的数据格式及读取

读bmp图片:头文件为66字节。。。怎么用c语言来读取数据啊,网上的代码我看不懂。新手,希望能写明白些

关于BMP