надеюсь, кто-то здесь может помочь. Моя проблема заключается в следующем:
Я создаю файлы, которые содержат двоичные данные. В начале каждого файла находится двоичный заголовок, который содержит информацию о содержимом файла. Заголовок файла имеет фиксированный размер, 52 байта. Заголовок содержит определенные фрагменты информации с определенными смещениями байтов в заголовке, однако некоторые фрагменты информации охватывают только части байта, скажем, 3 бита.
Например:
Байт 1-4 = длина файла
Байт 5-8 = длина заголовка
Байт 8-9 = информация о версии
Байт 10-13 = время создания файла
бит 1-4 = месяц (1-12)
бит 5-9 = день (1-31)
бит 10-14 = час (0-23)
бит 15-20 = минута (0-59)
бит 21 = направление смещения UTC
бит 22-26 = час смещения UTC
бит 27-32 = минута смещения UTC
так далее…
Некоторые значения определяются статически, некоторые определяются во время выполнения. Я попытался создать «карту» заголовка, определяющую количество битов, которые должен потреблять атрибут, и значение, представленное битами. Они хранятся в векторе пар int, значением является int_pair.first, а число битов — int_pair.second. Затем я преобразовываю предоставленные значения (все целые числа) в двоичный формат и вставляю двоичную запись в поток строк. Затем я создаю набор битов из строкового представления двоичного значения и записываю его в файл. Моя проблема в том, что байты не отображаются в выходном файле в правильном порядке.
Я опущу метод для получения значений и просто предоставлю целые числа в моем примере, и для краткости урежу некоторую информацию в заголовке (поэтому в этом примере заголовок составляет 14 байтов, а не 52), но здесь примерно что я делаю
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <bitset>
#include <vector>
#include <algorithm>
int main ()
{
vector<pair<int,int>> header_vec;
header_vec.push_back(make_pair(9882719,32)); // file length
header_vec.push_back(make_pair(52,32)); // header length
header_vec.push_back(make_pair(6,3)); // high release identifier
header_vec.push_back(make_pair(4,5)); // high version identifier
header_vec.push_back(make_pair(6,3)); // low release identifier
header_vec.push_back(make_pair(4,5)); // low version identifier
// file open timestamp
header_vec.push_back(make_pair(9,4)); // month
header_vec.push_back(make_pair(6,5)); // day
header_vec.push_back(make_pair(19,5)); // hour
header_vec.push_back(make_pair(47,6)); // min
header_vec.push_back(make_pair(0,1)); // utc direction
header_vec.push_back(make_pair(0,5)); // utc offset hours
header_vec.push_back(make_pair(0,6)); // utc offset minutes
ostringstream oss;
// convert each integer to binary representation
for ( auto i : header_vec )
{
for (unsigned int j(i.second-1); j != -1; --j)
{
oss << ((i.first &(1 << j)) ? 1 : 0);
}
}
// copy oss
string str = oss.str();
// create bitset
bitset<112> header_bits(string(str.c_str()));
// write bitset to file
ofstream output("header.out", ios::out | ios::binary );
output.write( reinterpret_cast<char *>(&header_bits), 14);
output.close();
return 0;
}
Теперь, по большей части, этот метод работает, за исключением того, что биты обращены. Если я посмотрю на выходной файл в FM, я ожидаю увидеть это:
File: header.out (0x0e bytes)
Byte: 0x0
00 00 96 cc 5f 00 00 00 34 c4 c4 93 4e f0 00 ..._...4...N...O
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
Когда на самом деле я вижу это:
File: header.out (0x0e bytes)
Byte: 0x0
00 00 f0 4e 93 c4 c4 34 00 00 00 5f cc 96 00 @O...N...4..._..
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
Я попытался изменить str до создания набора битов, но это также не дает желаемого результата.
Я полагаю, что недостаточно разбираюсь в битах, чтобы понять, почему это происходит. Любой вклад приветствуется! Кроме того, если есть другой способ сделать это, пожалуйста, поделитесь!
Заранее спасибо…
-J
Написание bitset<>
непосредственно как дамп памяти, безусловно, является непереносимым, о чем свидетельствует необходимость reinterpret_cast<>
, Другими словами, даже если данные расположены в хорошем блоке, вы не знаете, как это сделать.
Если бы я был вами, я бы написал более тупую функцию для извлечения фрагментов из 8 битов из набора битов и записи их в виде байтов в файл, используя обычный оператор доступа [].
Что касается другого подхода, то, что я обычно делаю, когда хочу прочитать / записать двоичный файл, — это определить структуру или набор структур, которые отображаются непосредственно в макет файла.
Например:
struct Timestamp
{
int month:4;
int day:5;
int hour:5;
int minute:6;
int utcOffsetDirection:1;
int utcOffsetHour:5;
int utcOffsetMinute:5;
};
Почему вы просто не используете структура битового поля, так что вы просто читаете и пишете в структуру, не беспокоясь о «разборе битов». Просто будьте осторожны с выравниванием памяти. Убедитесь, что вы добавили некоторые отступы, чтобы соответствовать слову бондарий
struct timestamp{
unsigned mont:4;
unsigned day:5;
unsigned hour:5;
unsigned minute:6;
unsigned utc:1;
unsigned utc_hour:5;
unsigned utc_min:6
};struct header{
int32_t file_length;
int32_t header_lenght;
int16_t version;
timestamp tmsp;
};