如何读取二进制文件的块(未知大小)

How to read chunks(of unknown size) of a binary file?

本文关键字:未知 二进制文件 读取 何读取      更新时间:2023-10-16

我对二进制文件有点困惑,我知道数据存储在二进制文件中的块中,根据我通过实验的知识,我发现如果我们有一个带有这样的成员变量的结构:

struct student{
int Roll_No;
char Name[10];
}

然后,在使用内容更新变量并将其保存在二进制文件中后,二进制文件为 14 字节、10 字节 char 和 4 个 int,因此如果我们在 hexeditor 中分析文件,该文件有 4 个字节保留用于 Roll_no 和 10 字节保留用于填充填充内容的 Name,其他可以被视为文件中的点, 我的意思是,如果我们像上面这样使用结构/类创建一个程序,并且在将内容保存到文件后,文件大小与我们创建的结构相同,我的意思是 int 的 4 和 char 的 10,所以据我所知,如果我创建了一个新的图像格式,例如。(点)。MyIMG,从我的程序的结构/类是这样的

struct MyIMG{
char Header[5];
int width, height;
int Pixels[124000];
}

然后我的程序将创建一个大小为 49613 字节或 49 Kigabytes 的新文件(这是标题的 5,+(加)8 的 int 高度和宽度,+(加)4×124000 的 int 像素),像素是 4、8、100,或者它会写入整个 Pixel 数组的任何内容,如果为空,那么为什么这种效果在任何大型软件(如 MSpaint)上都不能相同, Adobe photoshop,他们做什么,这使得他们的程序写入文件的大小取决于存储的像素而不是空白数组......

编辑

:我现在已经编辑了我的问题,并明确定义了我的问题,请帮助我,提前感谢!!

.png 和 .bmp 等文件格式具有特定的格式。文件格式可以指定字节的布局(例如 4 字节表示宽度,4 字节表示高度,2MB 的 RGBA 像素数据或其他任何),或者格式可以为您提供有关各种对象大小的信息。

例如,TIFF 文件将指定文件中特定字节偏移处有一个数字标记。然后,这些标记包含有关图像数据的大小、位置和格式的信息。因此,您可能有一个固定大小的标头,上面写着"有一个从字节 100 开始的标签列表,它包含 40 个标签"。每个标签都是固定大小(比如 16 字节),因此您知道从字节 100 开始读取 40 个 16 字节块。然后,标签将包含诸如图像数据开头的字节偏移量、像素中有多少字节以及有多少像素等信息。由此,您可以在事先不知道整个格式是什么的情况下读取数据。

编写文件的代码必须选择自己的格式。 例如,在将student结构写入文件时,可以这样说:

size_t name_len = strlen(my_student.Name);
my_ofstream.write((const char*)&my_student, sizeof my_student - sizeof my_student.Name + name_len + 1);

然后,这会将名称写入二进制文件,并将第一个 0/NUL 字符写入二进制文件。 当读回文件时,程序可以从ifstream读取数据块,然后 - 知道student存储在某个偏移量处,使用strlen()在传入数据的.Name部分恢复长度,部分这样它只能将必要的数据复制到student对象, 并且还知道从哪里开始解析输入流中的下一个数据项:

char buffer[32768];
student my_student;
if (my_ifstream.read(buffer, sizeof buffer) && my_ifstream.gcount() > 5)
{
    // check for NUL without risking reading buffer[.gcount()]
    size_t pre_name_len = std::offsetof(student, name);
    const char* p_name = buffer + pre_name_len;
    const char* p_nul = strnchr(p_name,
                                std::min(10, my_ifstream.gcount() - pre_name_len),
                                '');
    if (p_nul == nullptr || *p_nul != '')
        throw std::runtime_error("file didn't contain complete student record");
    memcpy(my_student, buffer, p_nul - buffer + 1);
    // keep parsing input from p_nul + 1, not going past .gcount()
}

如您所见 - 扫描单个 NUL 同时跟踪从文件中读取的数据量有点痛苦,这样如果您得到损坏的输入文件就不会崩溃......

对于初学者来说,学习 boost 序列化库可能是最简单、更健壮的,它抽象了大部分低级 - 有些人会说 C 风格 - I/O、铸造和偏移计算,为您提供更干净的逻辑接口。