我有一組 .bin 檔案,其中包含正式指定格式的資料。我確切地知道每個欄位有多少位元組,例如名稱 = 40 個位元組,版本號 = 2 個位元組等。我還知道它們在檔案中的確切存盤順序(例如名稱,然后是版本號......)。
到目前為止,我可以將檔案中的資料加載到std::vector<unsigned char>串列中,然后逐步遍歷該資料并根據預期的位元組數讀取欄位。
問題是,如果我弄錯任何欄位(有很多不同的欄位),此方法很長并且容易出錯。
我看過并與人們討論過結構體打包、指標轉換和位域。我似乎無法讓他們一起作業。
如何將資料讀入我的緩沖區,然后在緩沖區上“覆寫”我的結構?然后所有欄位將根據我在結構中給定每個值的分配位欄位填充。
位域的問題是我不能接受字串。
建議或示例代碼將不勝感激。如果你只想發表評論,我可以給你代碼來展示我到目前為止所擁有的以及我正在努力實作的目標。
#include <vector>
int main()
{
//File data loaded by function call
std::vector<unsigned char> fileData;
//How do I cast fileData to be a dataFields type?
}
struct dataFields
{
int ID : 8;
// Cannot use bit field for string type?
std::string name;
int versionNumber : 16;
int someOtherValue : 8;
}
由于作業原因,我無法提供我正在處理的確切代碼,但我覺得這總結了我在一個簡單的莊園中嘗試做得相當好的事情。
uj5u.com熱心網友回復:
不,您確實不能將位模式用于std::string,您無論如何都不想使用,因為它只包含幾個指標。
我在專案中使用的常用方法是為每種記錄型別設定 POD 結構。然后負責{反}序列化的最低層僅在 POD 和位元組之間進行轉換。任何 C 邏輯,likestd::string或 variable-lengthstd::vector都在更高級別處理。
#include <array>
#include <type_traits>
#include <cstdint>
#include <cstring>
struct Record{
std::uint8_t ID;
std::array<char,40> name;
std::uint16_t versionNumber;
std::uint8_t someOtherValue;
};
static_assert(sizeof(Record)==46);
static_assert(offsetof(Record,name)==1);
在我的世界中,我嘗試Record尊重sizeof(E)每個元素的標準對齊方式。如果需要,您可以添加打包修飾符。首選<cstdint>位域之前的型別。
我建議static_assert在 each 之后放置一堆s Record,以驗證其布局。否則總有一天會有人出現并試圖“清理”代碼,破壞一切。它還很好地為讀者記錄了協議。
一個缺點是這不容易支持將可變長度成員放在中間或擁有多個成員,但我從來沒有必要這樣做,保持資料包簡單。
此外,我只是決定協議的固定位元組序。如果有人需要其他東西,他們有責任傳遞正確編碼的Records 以進行序列化。
序列化助手:
template<typename T>
T read_value(const unsigned char*& ptr){
static_assert(std::is_standard_layout_v<T>);
T value;
std::memcpy(&value,ptr,sizeof(T));
ptr =sizeof(T);
return value;
}
template<typename T>
void write_value(unsigned char*& ptr, const T& value){
static_assert(std::is_standard_layout_v<T>);
std::memcpy(ptr,&value,sizeof(T));
ptr =sizeof(T);
}
負責{反}序列化的最低層可能如下所示:
void deserialize_stream(const unsigned char* bytes){\
// Output is bunch of POD types.
auto record1 = read_value<Record>(bytes);
auto record2 = read_value<Record>(bytes);
}
void serialize_stream(unsigned char* bytes){
// Input is a list of POD types to serialize.
Record record1{1,"Foo",12,42};
Record record2{2,"Bar",14,28};
write_value(bytes,record1);
write_value(bytes,record2);
}
例子
int main() {
// Just a example, CHECK SIZE in real world.
std::array<unsigned char,1024> buffer;
serialize_stream(buffer.data());
deserialize_stream(buffer.data());
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/346449.html
