バイト整列されていないデータを含むファイルがあり、そのファイルにシーク(3ビットなど)してから、バッファに読み込みを開始したい。これを行うための「簡単な」方法はありますか?ファイルにn個のビットをシークする(C++)
可能であれば、バッファ内の各文字をビットシフトしないようにします。
バイト整列されていないデータを含むファイルがあり、そのファイルにシーク(3ビットなど)してから、バッファに読み込みを開始したい。これを行うための「簡単な」方法はありますか?ファイルにn個のビットをシークする(C++)
可能であれば、バッファ内の各文字をビットシフトしないようにします。
非常に興味深いプラットフォームを使用していない限り、ファイルにはバイトが含まれています。そしてあなたはそれを一度に1バイト読む。したがって、ビットシフトなしでそれを行う方法はありません。最も簡単な方法は、私が考えることができるビットシフトを非表示にするには、以前に読み込まれたバイトを格納し、シフト "バックシーン"を入力イテレータを作ることです。
これが答えです。私は誰かがちょっとしたハックを知ってくれることを願っていました。 Richard HodgesとMarcinJędrzejewskiに感謝します。 – user102569
std::ifstreamはcharTをcharに特化しており、標準で提供されるデータの最小チャンクです。ビットレベルのファイルにアクセスするための標準的な低レベルの方法はありません。ファイルの少なくとも一部を読んで、分析をコードで行う必要があります。
あなたはgoogleで少しずつ読むことができるいくつかのstd :: streamアダプタがありますが、本当に必要かどうかはわかりません。私が見つけた一つがここにある:http://stanford.edu/~stepp/cppdoc/ibitstream-class.html
[編集]
以下はビットフィールドを持つ構造体を使用して、このようなファイルを読み込むサンプルです:
liveここ
#include <iostream>
#include <fstream>
#include <cassert>
#include <vector>
int main()
{
// Write test data
std::vector<bool> bit;
bit.push_back(0);
bit.push_back(0);
bit.push_back(0);
// Write test byte data, it is padded by 3 bits in front
for (int n = 0; n < 80 * 13; ++n)
bit.push_back((n/8 % 2)==0);
std::ofstream ofs("test.data", std::ifstream::binary);
for (auto it = bit.begin(); it != bit.end();) {
char toWrite = 0;
for (int n = 7; it!=bit.end() && n >= 0; --n, ++it) toWrite |= *it << n;
ofs.write(&toWrite, 1);
}
ofs.close();
// Read data
union S {
struct {
unsigned short pad : 5;
unsigned short dat : 8;
unsigned short oth : 3;
} inner;
char bytes[2];
} data;
// Create bit vector to verify if reading is correct.
std::vector<bool> bit2;
bit2.push_back(0); // First three bits are padding
bit2.push_back(0);
bit2.push_back(0);
std::ifstream ifs("test.data", std::ifstream::binary);
while(ifs.read(data.bytes, sizeof(data.bytes))) {
std::swap(data.bytes[0], data.bytes[1]);
// std::cout << data.inner.dat << ", ";
for (int n = 7; n >= 0; --n) bit2.push_back(data.inner.dat & (1 << n));
ifs.seekg(-1, ifs.cur);
}
assert(bit == bit2);
}
私は信じて、この構造体は2バイトのサイズを持っています。ポスターはバイト単位でデータを読み込みたいのですが、最初のバイトの3番目のビットから開始します。 – grisumbras
@グリムブラブあなたが正しいです、私はその部分を削除しました – marcinj
は非常に単純ですforward_only istreamイテレータをラップするbit_iterator。個々のビットを単語に抽出することができます。
正しい方向に動くのに十分なはずです。
#include <iostream>
#include <iterator>
#include <iomanip>
#include <sstream>
// forward-only iterator for simplicity
template<class Iter>
struct bit_iterator
{
using word_type = typename Iter::value_type;
static constexpr int end_bit = sizeof(word_type) * 8;
bit_iterator(Iter underlying) : _iter(underlying) {};
word_type operator*() {
if (_bitnum == end_bit)
{
_word = *_iter++;
_bitnum = 0;
}
auto ret = (_word & (1 << _bitnum++)) ? 1 : 0;
return ret;
}
bit_iterator& operator++() {
return *this;
}
bit_iterator& operator++(int) {
return *this;
}
Iter underlying() const {
return _iter;
}
Iter _iter;
word_type _word;
int _bitnum = end_bit;
};
template<class Iter>
auto make_bit_iterator(Iter iter)
{
return bit_iterator<Iter>(iter);
}
template<class Word, class Iter>
Word get_bits(Iter& iter, size_t bits = sizeof(Word) * 8)
{
Word acc = 0;
for (; bits ; --bits)
{
acc = (acc << 1) | *iter++;
}
return acc;
}
int main(int argc, char * argv[])
{
std::istringstream is("abcdefghijklmnop");
auto i = make_bit_iterator(std::istream_iterator<char>(is));
auto first_three = get_bits<char>(i, 3);
std::cout << std::hex << int(get_bits<std::uint8_t>(i)) << std::endl;
std::cout << std::hex << get_bits<std::int32_t>(i) << std::endl;
std::cout << std::hex << get_bits<std::uint16_t>(i) << std::endl;
return 0;
}
期待される結果:
32
36313533
3730
"バイト整列されていないデータ" どのようにそれは可能ですか? – Pierre
あなたは、あなたが注意していることを避けるつもりはありません。どちらかといえば、シフトやマスキングがメニューにあります。 – WhozCraig
ハードウェアの製造元に相談する必要があります。 – Ajay