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

时间:2016-04-05 06:27:33

标签: c++ binaryfiles

我有一个文件,其中包含非字节对齐的数据,我想在文件中寻找(例如3位),然后开始将字符读入缓冲区。有没有"容易"这样做的方法?

我希望尽可能避免在缓冲区中对每个字符进行位移。

3 个答案:

答案 0 :(得分:3)

除非您使用的是非常有趣的平台,否则您的文件包含字节。你一次读一个字节。所以如果没有位移,就没有办法做到这一点。 隐藏我想到的位移的最简单方法是创建一个输入迭代器,用于存储先前读取的字节并在“幕后”进行移位。

答案 1 :(得分:0)

std::ifstream专门用于charT to char,这是标准提供的最小数据块。我知道在位级访问文件没有标准的低级方法。您必须至少阅读文件的一部分并在代码中进行分析。

你在google上找到了一些std :: stream适配器,这些适配器允许一点一点地阅读,但我不确定你是否真的需要它。我找到的就是:http://stanford.edu/~stepp/cppdoc/ibitstream-class.html

[编辑]

下面是一个读取此类文件的示例,其中使用带有位域的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);
}

答案 2 :(得分:0)

这是一个非常简单的bit_iterator,它包装了一个forward_only istream迭代器。它允许将单个位提取为单词。

这足以让你朝着正确的方向前进。

#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