如何在 C++ 中对二进制数据使用 >> 和 << 运算符?

Car*_*arl 5 c++ stream

有没有办法使用这些运算符来输入和输出二进制数据?我想这样做的原因是它使代码可读。例如:infile>>filedecrypter>>metadataparser>>audiodecoder>>effects>>soundplayer;

Joh*_*itb 2

事实上,如果库或您的代码提供了重载operator<<operator>>使其正常工作,那么这是可以做到的。关于如何做到这一点的简单示例:

class transformer {
    public:
    virtual std::iostream& transform(std::iostream&) = 0;
};

class noise : public transformer {
    public:
    virtual std::iostream& transform(std::iostream&) {
         /* extract, change and put into again */
    }
};


class echo : public transformer {
    public:
    virtual std::iostream& transform(std::iostream&) {
         /* extract, change and put into again */
    }
};

std::iostream& operator>>(std::iostream& io, transformer& ts) {
    return ts.transform(io);
}

int main() {
    std::stringstream data;
    std::ifstream file("sound.wav");

    noise n; echo e;

    data << file.rdbuf();
    data >> n >> e;
    /* pipelined data now ready to be played back */
}
Run Code Online (Sandbox Code Playgroud)

使用 pure 的问题std::istream是您会读取,但随后您将无法将转换后的数据放回管道中的下一步。因此我std::iostream在这里使用。这种方法似乎效率不高,因为每个操作员>>调用都会提取整个数据,然后再次放入。

要采用更高效的方式进行流式传输,需要创建一个expression template. 这意味着,在operator>>调用时,您还没有进行转换,但您返回的表达式类型将记录其类型内的操作链:

typedef transform< echo< noise< istream > > > pipeline;
std::ifstream file("file.wav");
pipeline pipe(file);
int byte = pipe.get();
Run Code Online (Sandbox Code Playgroud)

就是这种类型的一个例子。管道的结构被解码为类型本身。因此,管道中不再需要虚拟函数。它不是按需构建的,而是在这里使用 typedef 来展示原理。对这样的系统进行编程并不容易。因此,您可能应该研究现有系统,例如 Boost.Iostreams(见下文)。为了让您了解它的样子,这是我刚刚为您编写的一个示例:):

#include <iostream>

template<typename T>
struct transformer {
    int get() {
        return static_cast<T*>(this)->read();
    }
};

struct echot {
    template<typename Chain>
    struct chain : transformer< chain<Chain> > {
        Chain c;

        int read() {
            return c.get() + 1;
        }

        chain(Chain const& c):c(c) { }
    };
} echo;

struct noiset {
    template<typename Chain>
    struct chain : transformer< chain<Chain> > {
        Chain c;

        int read() {
            return c.get() * 2;
        }

        chain(Chain c):c(c) { }
    };
} noise;


template<typename T>
typename T::template chain<std::istream&> operator>>(std::istream& is, T) {
    return typename T::template chain<std::istream&>(is);
}

template<typename T, typename U>
typename U::template chain<T> operator>>(T t, U u) {
    return typename U::template chain<T>(t);
}

int main() {
    std::cout << (std::cin >> echo >> noise).get() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

此处输入 0 会产生 ASCII 码 48,加 1,再乘以 2,得到值 98,这也是最终输出。我认为您同意这不是初学者想要编写的代码。所以也许可以考虑一下boost。

Boost 有一个复杂的 iostreams 库,可以做很多事情。我相信您会找到适合的东西。Boost.Iostreams