簡體   English   中英

將二進制文件緩沖區的塊讀入不同類型

[英]Read blocks of a binary file buffer into different types

我試圖將二進制文件讀入內存,然后像這樣使用它:

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)。

如果您不打算使用序列化庫,那么我建議為每個類添加序列化支持:

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

編輯1:原因是不直接寫結構

在C和C ++中,結構的大小可能不等於其成員大小的總和。
允許編譯器在成員之間插入填充或未使用的空間,以便成員在地址上對齊。

例如,32位處理器喜歡在4字節邊界上獲取內容。 在結構中有一個char后跟一個int會在相對地址1上生成int ,這不是4的倍數。編譯器會填充結構,以便int在相對地址4上排列。

結構可能包含指針或包含指針的項目。
例如, std::string類型的大小可能為40,盡管字符串可能包含3個字符或300.它有一個指向實際數據的指針。

字節序。
對於多字節整數,一些處理器如最重要字節(MSB),又名Big Endian,首先(人類讀取數字的方式)或最低有效字節,即Little Endian。 Little Endian格式比Big Endian需要更少的讀取電路。

編輯2:變體記錄

在輸出數組和容器之類的東西時,您必須決定是要輸出完整容器(包括未使用的插槽)還是僅輸出容器中的項目。 僅輸出容器中的項目將使用變體記錄技術。

輸出變量記錄的兩種技術:數量后跟項目或項目后跟哨兵。 后者是如何編寫C風格的字符串,其中標記是一個空字符。

另一種技術是輸出項目數量,然后輸出項目。 所以如果我有6個數字,0,1,2,3,4,5,輸出將是:
6 //項目數量
0
1
2
3
4

在上面的Load_From_Buffer方法中,我將創建一個臨時來保存數量,寫出來,然后跟隨容器中的每個項目。

你可以為你的結構重載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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM