iostream的二进制版本 [英] Binary version of iostream

查看:138
本文介绍了iostream的二进制版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经写输入输出流的二进制版本。它本质上允许你写的二进制文件,但是你可以对这些文件的格式的控制权。用法示例:

I've been writing a binary version of iostreams. It essentially allows you to write binary files, but gives you much control over the format of the file. Example usage:

my_file << binary::u32le << my_int << binary::u16le << my_string;

会写my_int为32位无符号整数,my_string作为一种长度 - prefixed字符串(其中preFIX是u16le。)读取文件回来,你会翻转箭头。伟大工程。不过,我打在设计上颠簸,我依然对关于它的栅栏。因此,时问左右。 (我们使几个假设,如8位字节,二进制补整数,和IEEE漂浮的时刻。)

Would write my_int as a unsigned 32-bit integer, and my_string as a length-prefixed string (where the prefix is u16le.) To read the file back, you would flip the arrows. Works great. However, I hit a bump in the design, and I'm still on the fence about it. So, time to ask SO. (We make a couple of assumptions, such as 8-bit bytes, 2s-complement ints, and IEEE floats at the moment.)

输入输出流,引擎盖下,使用streambuf。这是一个梦幻般的设计确实 - iostreams的code的序列化 INT 成文字,让底层的流缓冲处理其余部分。因此,你会得到清点,fstreams,stringstreams等,所有这些,无论是输入输出流和的streambuf,都是模板,通常对char,但有时也可作为WCHAR。我的数据,但是,是一个字节流,其中最重$ P $由psented unsigned char型

iostreams, under the hood, use streambufs. It's a fantastic design really -- iostreams code the serialization of an 'int' into text, and let the underlying streambuf handle the rest. Thus, you get cout, fstreams, stringstreams, etc. All of these, both the iostreams and the streambufs, are templated, usually on char, but sometimes also as a wchar. My data, however, is a byte stream, which best represented by 'unsigned char'.

我的第一次尝试是为模板,根据 unsigned char型的类。 的std :: basic_string的模板不够好,但流缓冲没有。我遇到了一些问题与命名类 codeCVT ,这是我永远无法得到遵循 unsigned char型主题。这就产生了两个问题:

My first attempts were to template the classes based on unsigned char. std::basic_string templates well enough, but streambuf does not. I ran into several problems with a class named codecvt, which I could never get to follow the unsigned char theme. This raises two questions:

1)为什么是流缓冲负责这样的事情?这似乎是code-转换骗出路流缓冲的责任 - 的streambuf应采取流,并从中缓存数据/。而已。有些事情是如此高的水平,code转换感觉它应该属于的iostream

1) Why is a streambuf responsible for such things? It seems like code-conversions lie way out of a streambuf's responsibility -- streambufs should take a stream, and buffer data to/from it. Nothing more. Something as high level as code conversions feels like it should belong in iostreams.

因为我不能让模板的streambuf与unsigned char型的工作,我回到了焦炭,而只是铸造焦炭/ unsigned char型之间的数据。我试图尽量减少铸件的数量,原因是显而易见的。大部分数据在read()或write()函数,然后调用底层的流缓冲基本上卷起。 (在此过程中使用强制)读功能基本上是:

Since I couldn't get the templated streambufs to work with unsigned char, I went back to char, and merely casted data between char/unsigned char. I tried to minimize the number of casts, for obvious reasons. Most of the data basically winds up in a read() or write() function, which then invoke the underlying streambuf. (And use a cast in the process.) The read function is basically:

size_t read(unsigned char *buffer, size_t size)
{
    size_t ret;
    ret = stream()->sgetn(reinterpret_cast<char *>(buffer), size);
    // deal with ret for return size, eof, errors, etc.
    ...
}

好的解决方案,不好解决?

Good solution, bad solution?


前两个问题表明需要更多的信息。首先,项目,如boost ::系列化被看着,但他们在更高层次上存在,它们定义自己的二进制格式。这是更为读/在较低的水平,它是希望定义的格式书写,或格式已经定义,或大容量的元数据不是必需的或期望的。

The first two questions indicate that more info is needed. First, projects such as boost::serialization were looked at, but they exist at a higher level, in that they define their own binary format. This is more for reading/writing at a lower level, where it is wished to define the format, or the format is already defined, or the bulk metadata is not required or desired.

二,一些人询问了二进制:: u32le 修改。这是保存所需的字节顺序和宽度,此刻,也许签署岬在将来的类的实例。流认为,课程的最后,通过实例的副本,并且使用了序列化。这是一个有点变通办法的,我试过orginally超载的&lt;&LT;运营商正是如此:

Second, some have asked about the binary::u32le modifier. It is an instantiation of a class that holds the desired endianness and width, at the moment, perhaps signed-ness in the future. The stream holds a copy of the last-passed instance of that class, and used that in serialization. This was a bit of a workaround, I orginally tried overloading the << operator thusly:

bostream &operator << (uint8_t n);
bostream &operator << (uint16_t n);
bostream &operator << (uint32_t n);
bostream &operator << (uint64_t n);

但在当时,这似乎并没有工作。我有几个问题不明确的函数调用。这是常量尤其如此,虽然可以作为一张海报建议,铸造或仅仅是其声明为常量&LT;&型GT; 。我似乎记得有一些其他较大的问题,但是。

However at the time, this didn't seem to work. I had several problems with ambiguous function call. This was especially true of constants, although you could, as one poster suggested, cast or merely declare it as a const <type>. I seem to remember that there was some other larger problem however.

推荐答案

我同意合法化。我需要做的几乎一模一样,你在做什么,看着超载&LT;&LT; / &GT;&GT; ,但来到这的iostream只是没有设计来适应它的结论。一方面,我不想有子类的流类是能够定义我的过载。

I agree with legalize. I needed to do almost exactly what you're doing, and looked at overloading << / >>, but came to the conclusion that iostream was just not designed to accommodate it. For one thing, I didn't want to have to subclass the stream classes to be able to define my overloads.

我的解决方案(只需要暂时连载一台机器上的数据,因此并没有需要处理字节序)是基于这种模式:

My solution (which only needed to serialize data temporarily on a single machine, and therefore did not need to address endianness) was based on this pattern:

// deducible template argument read
template <class T>
void read_raw(std::istream& stream, T& value,
    typename boost::enable_if< boost::is_pod<T> >::type* dummy = 0)
{
    stream.read(reinterpret_cast<char*>(&value), sizeof(value));
}

// explicit template argument read
template <class T>
T read_raw(std::istream& stream)
{
    T value;
    read_raw(stream, value);
    return value;
}

template <class T>
void write_raw(std::ostream& stream, const T& value,
    typename boost::enable_if< boost::is_pod<T> >::type* dummy = 0)
{
    stream.write(reinterpret_cast<const char*>(&value), sizeof(value));
}

我再往重载read_raw / write_raw任何非POD类型(例如字符串)。请注意,只有read_raw的第一个版本需要被超载;如果你正确使用ADL,第二(1-ARG)的版本可以调用后面定义2 ARG过载和其他命名空间。

I then further overloaded read_raw/write_raw for any non-POD types (e.g. strings). Note that only the first version of read_raw need be overloaded; if you use ADL correctly, the second (1-arg) version can call 2-arg overloads defined later and in other namespaces.

写例如:

int32_t x;
int64_t y;
int8_t z;
write_raw(is, x);
write_raw(is, y);
write_raw<int16_t>(is, z); // explicitly write int8_t as int16_t

阅读例如:

int32_t x = read_raw<int32_t>(is); // explicit form
int64_t y;
read_raw(is, y); // implicit form
int8_t z = numeric_cast<int8_t>(read_raw<int16_t>(is));

这并不是因为重载运算符性感,事情不适合在一行一样轻松(我倾向于避免无论如何,因为调试断点是面向行的),但我认为它横空出世更简单,更明显,并没有太多的更详细。

It's not as sexy as overloaded operators, and things don't fit on one line as easily (which I tend to avoid anyway, since debug breakpoints are line-oriented), but I think it turned out simpler, more obvious, and not much more verbose.

这篇关于iostream的二进制版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆