简体   繁体   English

在文件中寻找n个位(C ++)

[英]Seek n number of bits into a file (C++)

I have a file which contains data which is not byte aligned and I want to seek (eg 3 bits) into the file and then start reading chars into a buffer. 我有一个文件,其中包含非字节对齐的数据,我想在文件中寻找(例如3位),然后开始将字符读入缓冲区。 Is there an "easy" way to do this? 是否有捷径可寻?

I want to avoid bit-shifting each char in the buffer if possible. 我希望尽可能避免在缓冲区中对每个字符进行位移。

Unless you're using a very interesting platform, your file contains bytes. 除非您使用的是非常有趣的平台,否则您的文件包含字节。 And you read it one byte at a time. 你一次读一个字节。 So there is no way to do it without bit shifting. 所以如果没有位移,就没有办法做到这一点。 The simplest way to hide the bit shifting I could think of, is to make an input iterator that stores the previously read byte and does the shift "behind the scenes". 隐藏我可以想到的位移的最简单方法是创建一个输入迭代器,它存储先前读取的字节并在“幕后”进行移位。

std::ifstream is specialized on charT to char, which is the smallest chunk of data provided by standard. std :: ifstream专门用于charT到char,这是标准提供的最小数据块。 There is no standard low level way I know of to access files on bit level. 我知道在位级访问文件没有标准的低级方法。 You will have to read at least parts of the file and do the analysis in code. 您必须至少阅读文件的一部分并在代码中进行分析。

You find on google some std::stream adaptors which will allow for reading bit by bit, but I am not sure if you really need this. 你在google上找到了一些std :: stream适配器,它们可以一点一点地读取,但我不确定你是否真的需要它。 One I have found is here: http://stanford.edu/~stepp/cppdoc/ibitstream-class.html 我发现的是: http//stanford.edu/~stepp/cppdoc/ibitstream-class.html

[edit] [编辑]

Below is a sample reading such file with the use of struct with bitfields: 下面是使用带有位域的struct读取此类文件的示例:

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

Here's a very simplistic bit_iterator which wraps a forward_only istream iterator. 这是一个非常简单的bit_iterator,它包装了一个forward_only istream迭代器。 It allows extraction of individual bits into a word. 它允许将各个位提取为单词。

It should be enough to get you moving in the right direction. 它应该足以让你朝着正确的方向前进。

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

expected results: 预期成绩:

32
36313533
3730

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM