C++中与Java ByteBuffer相等的类型是什么?

29

我正在寻找一个与Java ByteBuffer“等价”的C++工具。

我可能忽略了一些明显的东西,或者只需要一个独立的用例来澄清。我已经查看了iostream系列,并且看起来它可能提供了一个基础。具体来说,我想要能够:

  • 从字节数组/指针构建缓冲区并从缓冲区获取原语,例如getByte、getInt
  • 使用基元构建缓冲区,例如putByte、putInt,然后获取字节数组/指针。

йңҖиҰҒжіЁж„Ҹзҡ„жҳҜпјҢеңЁ get(T) е’Ң put(T) дёӯпјҢT дёҚжҳҜ byteпјҢиҖҢжҳҜе…¶д»–еҺҹе§Ӣзұ»еһӢпјҢжҜ”еҰӮ intгҖҒfloat е’Ң shortгҖӮ - Rob Kennedy
是的,那是我不幸的命名选择。我已经做出了更清晰的解释。 - user172783
6个回答

18
你可以使用stringbuffilebuf或者vector<char>

这是一个使用stringbuf的简单示例:

std::stringbuf buf;
char data[] = {0, 1, 2, 3, 4, 5};
char tempbuf[sizeof data];

buf.sputn(data, sizeof data); // put data
buf.sgetn(tempbuf, sizeof data); // get data

感谢 @Pete Kirkham 提出的通用函数思路。

#include <sstream>

template <class Type>
std::stringbuf& put(std::stringbuf& buf, const Type& var)
{
    buf.sputn(reinterpret_cast<const char*>(&var), sizeof var);

    return buf;
}

template <class Type>
std::stringbuf& get(std::stringbuf& buf, Type& var)
{
    buf.sgetn(reinterpret_cast<char*>(&var), sizeof(var));

    return buf;
}

int main()
{
    std::stringbuf mybuf;
    char byte = 0;
    int var;

    put(mybuf, byte++);
    put(mybuf, byte++);
    put(mybuf, byte++);
    put(mybuf, byte++);

    get(mybuf, var);
}

1
如果从缓冲区中提取的内容不是另一个字符数组,那么这将是一个更好的示例。ByteBuffer允许从字节缓冲区中提取其他原始类型,而不仅仅是字节。http://java.sun.com/j2se/1.4.2/docs/api/java/nio/ByteBuffer.html - Rob Kennedy
我以get(T)和put(T)作为示例的选择相当糟糕;我想从缓冲区中提取变量大小。std::stringbuf感觉像是正确的方向。谢谢。 - user172783
它是非字符型的。也许在这种情况下,std::streambuf是更好的选择,尽管它们两个都应该可行。 - user172783
3
啊哈。streambuf是一个抽象类,stringbuf只是被称为stringbuf,但这并不意味着它是基于字符的。它只是一个字节缓冲区。但元素的类型是char,这就是为什么被称为(string)buf的原因。 - Khaled Alshaya

8

stringstream提供基本的未格式化的getwrite操作,用于编写字符块。为了专门针对T,可以子类化或包装它,也可以提供独立的模板函数来使用适当大小的内存进行读取/写入。

template <typename T>
std::stringstream& put ( std::stringstream& str, const T& value )
{
    union coercion { T value; char   data[ sizeof ( T ) ]; };

    coercion    c;

    c.value = value;

    str.write ( c.data, sizeof ( T ) );

    return str;
}

template <typename T>
std::stringstream& get ( std::stringstream& str, T& value )
{
    union coercion { T value; char   data[ sizeof ( T ) ]; };

    coercion    c;

    c.value = value;

    str.read ( c.data, sizeof ( T ) );

    value = c.value;

    return str;
}

您可以为任何其他流或向量编写这样的模板 - 对于向量的情况,它需要使用insert而不是write。

1
不错的解决方案 :) 我认为流更多地是用来读写格式化数据的工具。为什么要像缓冲区一样使用流,在流内部还有一个缓冲区。尽管如此,我认为你的通用函数是一个很好的想法。 - Khaled Alshaya
我倾向于使用流,因为我喜欢将其强制转换为布尔值的方式和返回流以进行链式调用的习惯,而不是返回写入的字节数并且需要绕来绕去地测试它。 - Pete Kirkham

6
std::vector<char> bytes;

bytes.push_back( some_val ); // put

char x = bytes[N];           // get

const char* ptr = &bytes[0]; // pointer to array

4

如果写入者和读取者运行在不同的架构上,这似乎没有处理整数类型的字节顺序差异。我认为Java的ByteBuffer默认是大端字节序,但提供了改变字节顺序的能力。有其他选择吗? - Hoobajoob

3

感谢所有的意见,这些意见带来了一个非常简单的解决方案:


class ByteBuffer : std::stringbuf
{
public:
    template 
    size_t get( T &out)
    {
        union coercion { T value; char data[ sizeof ( T ) ]; };

        coercion c;

        size_t s= xsgetn( c.data, sizeof(T));

        out= c.value;

        return s;
    }

    template 
    size_t put( T ∈)
    {   
        union coercion { T value; char data[ sizeof ( T ) ]; };

        coercion c;

        c.value= in;

        return xsputn( c.data, sizeof(T));
    }

    size_t get( uint8_t *out, size_t count)
    {
        return xsgetn((char *)out, count);
    }

    size_t put( uint8_t *out, size_t count)
    {
        return xsputn((char *)out, count);
    }
};

使用示例:


void ByteBufferTest( void)
{
    ByteBuffer bb;

    float f= 4;
    uint8_t u8= 1;
    uint16_t u16= 2;
    uint32_t u32= 4;
    uint64_t u64= 8;

    bb.put(f);
    bb.put(u8);
    bb.put(u16);
    bb.put(u32);
    bb.put(u64);

    uint8_t array[19];

    bb.get( array, 19);

    // or

    bb.get(f);
    bb.get(u8);
    bb.get(u16);
    bb.get(u32);
    bb.get(u64);
}

3
我不喜欢您子类化 std::stringbuf 的想法。请改用组合方式。该命名空间中的大多数类型都不是为此设计的。此外,为什么要那样使用 size_t? - Arafangion

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接