如何正确读取和写入二进制文件?(C++)

How do I properly read and write Binary files? (C++)

本文关键字:C++ 二进制文件 何正确 读取      更新时间:2023-10-16

在这个程序中,我正在读取、操作和编写二进制位图文件。我正在尝试使用 C 样式文件来读取和写入这些文件。我还使用 new(( 和 delete 将内存动态分配到堆上,以便将该内存块写入另一个文件。 我认为当我在 for 循环中读取和写入二进制文件时我遇到了问题。不知何故,我在查看我的输出文件后被文件和信息标题覆盖。我只需要帮助理解为什么会发生这种情况。我所有其他代码都应该没问题。

#include <cstdint>
#include <cstdio>
#pragma pack(push, 2)
struct BitmapFileHeader {
uint16_t type;
uint32_t size;
uint16_t reserved_1;
uint16_t reserved_2;
uint32_t offset;
};
struct BitmapInfoHeader {
uint32_t size;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitcount;
uint32_t compression;
uint32_t imagesize;
uint32_t x_pixels_per_meter;
uint32_t y_pixels_per_meter;
uint32_t color_used;
uint32_t color_important;
};
#pragma pack(pop)
struct Pixel {
uint8_t blue;
uint8_t green;
uint8_t red;
};
int main(int argc, char* argv[])
{
if(argc != 3) {
printf("Usage : %s input_file output_filen", argv[0]);
return 1;
}
FILE *fin;
FILE *fout;
BitmapFileHeader bfh;
BitmapInfoHeader bih;
fin = fopen(argv[1], "rb");
if (nullptr == fin) {
perror(argv[1]);
return -1;
}
if (sizeof(BitmapFileHeader) != fread(
&bfh,
1,
sizeof(bfh),
fin
)) {
printf("Unable to read bitmap file header. n");
return -2;
}
if (sizeof(BitmapInfoHeader) != fread(
&bih,
1,
sizeof(bih),
fin
)) {
printf("Unable to read bitmap info header. n");
return -3;
}
printf("Size of File Header = %lun", sizeof(BitmapFileHeader));
int8_t first = (bfh.type >> 8) & 0xff;
int8_t second = bfh.type & 0xff;
if ( (first != 'M') && (second != 'B') ){
printf("Input file is not a Bitmap file. n");
return -4;
}
printf("File type = %c%cn", first, second);
printf("File size = %un", bfh.size);
printf("File offset = %un", bfh.offset);
printf("File width = %un", bih.width);
printf("Info size = %un", bih.size);
uint32_t padding_bytes = 0;
uint32_t row_bytes_final = bih.width * sizeof(Pixel);
uint32_t row_bytes_initial = row_bytes_final;
do{
uint32_t rem = row_bytes_final % 4;
if (rem != 0) {
row_bytes_final += 1;
}
padding_bytes = row_bytes_final - row_bytes_initial;
} while( (row_bytes_final % 4) != 0);

fseek(fin, bfh.offset, SEEK_SET);
Pixel *p = new Pixel[bih.height * bih.width];
for (uint32_t i = 0; i < (bih.height); i++) {
for (uint32_t j = 0; j < bih.width; j++) {
fread(&p[i], 1, sizeof(p), fin);
i++;
//Something I don't understand is wrong here. 
}
fseek(fin, padding_bytes, SEEK_CUR);
}
fclose(fin);

fout = fopen(argv[2], "wb");
if(nullptr == fout) {
perror(argv[2]);
return -5;
}
if( sizeof(BitmapFileHeader) != fwrite(
&bfh, 
1, 
sizeof(bfh), 
fout
)) {
printf("Unable to write bitmap file header.n");
return -6;
}
if( sizeof(BitmapInfoHeader) != fwrite(
&bih, 
1, 
sizeof(bih), 
fout
)) {
printf("Unable to write bitmap info header.n");
return -7;
}
fseek(fout, bfh.offset, SEEK_SET);
for (uint32_t i = 0; i < (bih.height) ; i++) {
for (uint32_t j = 0; i < bih.width; j++) {
fwrite(&p[i], 1, sizeof(p), fout);
i++;
//same problem
}
fseek(fout, padding_bytes, SEEK_CUR);
}
fclose(fout);
delete p;

//fseek(fin, bfh.offset, SEEK_SET);
//Pixel p;
//fread(&p, 1, sizeof(p), fin);
//printf("R = %u, G = %u, B = %un", p.red, p.green, p.blue);
return 0;
}

如果我将文件指针移动到偏移量,如何覆盖输出文件的标头?

我在您的代码中看到以下问题:

问题1

您使用错误的参数来sizeof

fread(&p[i], 1, sizeof(p), fin);

fwrite(&p[i], 1, sizeof(p), fout);

它们需要sizeof(p[i])sizeof(p[0])sizeof(Pixel)。我更喜欢sizeof(p[0])因为无论p[0]类型如何,它都可以工作。

问题2

您在 中有拼写错误

for (uint32_t j = 0; i < bih.width; j++) {

它需要

for (uint32_t j = 0; j < bih.width; j++) {
//                  ^^^ Fix

问题3

您没有使用正确的索引来读取p和从p写入。

for (uint32_t i = 0; i < bih.height; i++) {
for (uint32_t j = 0; j < bih.width; j++) {
// Using p[i] is not correct. You need to use the right index.
// sizeof(p[0]) is just as good as sizeof(p[index]) here.
uint32_t index = i*bih.width + j;
fread(&p[index], 1, sizeof(p[0]), fin);
}
fseek(fin, padding_bytes, SEEK_CUR);
}

写入循环需要以类似的方式修复。

for (uint32_t i = 0; i < bih.height; i++) {
for (uint32_t j = 0; j < bih.width; j++) {
uint32_t index = i*bih.width + j;
fwrite(&p[index], 1, sizeof(p[0]), fout);
}
fseek(fout, padding_bytes, SEEK_CUR);
}

我认为fread(&p[i], 1, sizeof(p), fin);应该fread(&p[i], 1, sizeof(Pixel), fin);

指针的大小(基于体系结构(通常为 4 或 8 个字节。 像素类为 3 个字节(包含 #pragma 个 pack(push, 1((。

可用于fread(&p[i], sizeof(Pixel), bih.width, fin);但请注意,排序和填充可能因不同的体系结构而异。