我正在尝试将二进制文件读入内存,然后像这样使用它:
struct myStruct {
std::string mystring; // is 40 bytes long
uint myint1; // is 4 bytes long
};
typedef unsigned char byte;
byte *filedata = ReadFile(filename); // reads file into memory, closes the file
myStruct aStruct;
aStruct.mystring = filedata.????
我需要一种使用偏移量访问二进制文件的方法,并在该偏移量处获得一定长度。
如果我将二进制文件数据存储在std :: string中,这很容易,但我认为使用它来存储二进制数据并不是一种好的处理方式。 (filedata.substr(offset, len))
合理广泛(IMO)搜索没有任何关联,任何想法?如果您认为有必要,我愿意更改存储类型(例如更改为std :: vector)。
答案 0 :(得分:3)
如果您不打算使用序列化库,那么我建议为每个类添加序列化支持:
struct My_Struct
{
std::string my_string;
unsigned int my_int;
void Load_From_Buffer(unsigned char const *& p_buffer)
{
my_string = std::string(p_buffer);
p_buffer += my_string.length() + 1; // +1 to account for the terminating nul character.
my_int = *((unsigned int *) p_buffer);
p_buffer += sizeof(my_int);
}
};
unsigned char * const buffer = ReadFile(filename);
unsigned char * p_buffer = buffer;
My_Struct my_variable;
my_variable.Load_From_Buffer(p_buffer);
其他一些有用的界面方法:
unsigned int Size_On_Stream(void) const; // Returns the size the object would occupy in the stream.
void Store_To_Buffer(unsigned char *& p_buffer); // Stores object to buffer, increments pointer.
使用模板,您可以扩展序列化功能:
void Load_From_Buffer(std::string& s, unsigned char *& p_buffer)
{
s = std::string((char *)p_buffer);
p_buffer += s.length() + 1;
}
void template<classtype T> Load_From_Buffer(T& object, unsigned char *& p_buffer)
{
object.Load_From_Buffer(p_buffer);
}
在C和C ++中,结构的大小可能不等于其成员大小的总和。
允许编译器在成员之间插入 padding 或未使用的空间,以便成员在地址上对齐。
例如,32位处理器喜欢在4字节边界上获取内容。在结构中有一个char
后跟int
会使int
在相对地址1上,这不是4的倍数。编译器会 pad 结构使int
排在相对地址4上。
结构可能包含指针或包含指针的项目。
例如,std::string
类型的大小可能为40,尽管字符串可能包含3个字符或300.它有一个指向实际数据的指针。
<强>字节序强>
对于多字节整数,一些处理器,如最高有效字节(MSB),a.k.a. Big Endian,首先(人类读数字的方式)或最低有效字节,a.k.a。Little Endian。 Little Endian格式比Big Endian需要更少的读取电路。
输出数组和容器之类的东西时,必须决定是要输出完整容器(包括未使用的插槽)还是只输出容器中的项目。仅输出容器中的项目将使用变体记录技术。
输出变量记录的两种技术:数量后跟项目或项目后跟哨兵。后者是如何编写C风格的字符串,其中标记是一个空字符。
另一种技术是输出项目数量,然后输出项目。所以如果我有6个数字,0,1,2,3,4,5,输出将是:
6 //项目数量
0
1
2
3
4
5
在上面的Load_From_Buffer方法中,我会创建一个临时来保存数量,写出来,然后跟随容器中的每个项目。
答案 1 :(得分:0)
你可以为你的结构重载std :: ostream输出操作符和std :: istream输入操作符,如下所示:
struct Record {
std::string name;
int value;
};
std::istream& operator>>(std::istream& in, Record& record) {
char name[40] = { 0 };
int32_t value(0);
in.read(name, 40);
in.read(reinterpret_cast<char*>(&value), 4);
record.name.assign(name, 40);
record.value = value;
return in;
}
std::ostream& operator<<(std::ostream& out, const Record& record) {
std::string name(record.name);
name.resize(40, '\0');
out.write(name.c_str(), 40);
out.write(reinterpret_cast<const char*>(&record.value), 4);
return out;
}
int main(int argc, char **argv) {
const char* filename("records");
Record r[] = {{"zero", 0 }, {"one", 1 }, {"two", 2}};
int n(sizeof(r)/sizeof(r[0]));
std::ofstream out(filename, std::ios::binary);
for (int i = 0; i < n; ++i) {
out << r[i];
}
out.close();
std::ifstream in(filename, std::ios::binary);
std::vector<Record> rIn;
Record record;
while (in >> record) {
rIn.push_back(record);
}
for (std::vector<Record>::iterator i = rIn.begin(); i != rIn.end(); ++i){
std::cout << "name: " << i->name << ", value: " << i->value
<< std::endl;
}
return 0;
}