简体   繁体   English

C ++文件IO:读取和写入16位字

[英]C++ File IO: Reading and Writing 16-bit Words

I want to write non-Unicode, 16-bit words to a file a read them back later. 我想将非Unicode 16位字写到文件中,稍后再读回去。 I know with a bit of byte manipulation I can do this in char mode using fstream::read() and fstream::write() . 我知道通过一些字节操作,我可以使用fstream::read()fstream::write()char模式下完成此操作。 What do I need to do to use 16-bit words directly? 直接使用16位字该怎么办?

For example, it seems I should be able to do the following: 例如,看来我应该能够执行以下操作:

 basic_ofstream<uint16_t> aw;
 aw.open("test.bin", ios::binary);
 uint16_t c[] = {0x55aa, 0x1188};
 aw.write(c, 2);
 aw.close();

 basic_ifstream<uint16_t> ax;
 ax.open("test.bin", ios::binary);
 uint16_t ui[2];
 ax.read(ui, 2);
 ax.close();
 cout << endl << hex << unsigned(ui[0]) << " " << unsigned(ui[1]) << endl;

gcc 4.4 output: gcc 4.4输出:

d 0

Vc++10 output: VC ++ 10输出:

CCCC CCCC

I've also tried using std::basic_filebuf<uint16_t> direct and got the same results. 我也尝试过直接使用std::basic_filebuf<uint16_t>并获得相同的结果。 Why? 为什么?

I'm actually surprised you got the streams instantiated to do any reading at all! 我真的很惊讶您实例化了流以进行任何阅读! What the result will be is possibly implementation defined (ie, you might find the behavior described in the compiler's documentation) but possibly it is just not specified (although not quite undefined). 结果可能是实现定义的(即,您可能会在编译器的文档中找到了描述的行为),但可能只是未指定(尽管不是很不确定)。 I don't think the stream classes are required to support instantiations for other types than char and wchar_t immediately, ie, without the user providing at least some of the facets. 我认为不需要流类立即支持charwchar_t以外的其他类型的实例化,即,无需用户提供至少一些方面。

The standard stream classes are templates on the character type but aren't easy to instantiate for any unsupported type. 标准流类是字符类型上的模板,但是对于任何不受支持的类型来说,实例化起来并不容易。 At bare minimum, you'd need to implement a suitable std::codecvt<int16_t, char, std::mbstate_t> facet converting between the external representation in byte and the internal representation. 至少,您需要实现一个合适的std::codecvt<int16_t, char, std::mbstate_t>构面在字节的外部表示和内部表示之间进行转换。 From the looks of it the two systems you tried have made different choices for their default implementation. 从外观上看,您尝试过的两个系统为其默认实现选择了不同的选择。

std::codecvt<internT, externT, stateT> is the facet used to convert between an external representation of characters and an internal representation of characters. std::codecvt<internT, externT, stateT>是用于在字符的外部表示和字符的内部表示之间转换的构面。 Streams are only required to support char which is considered to represent bytes as the external type externT . 流仅需要支持charchar被视为将字节表示为外部类型externT The internal character type internT can be any integral type but the conversion needs to be defined by implementing the code conversion facet. 内部字符类型internT可以是任何整数类型,但是需要通过实现代码转换方面来定义转换。 If I recall correctly, the streams can also assume that the state type stateT is std::mbstate_t (which is actually somewhat problematic because there is no interface defined for this type!). 如果我没stateT话,流还可以假定状态类型为stateTstd::mbstate_t (这实际上有点问题,因为没有为此类型定义接口!)。

Unless you are really dedicated in creating an I/O stream for your character type uint16_t , you probably want to read bytes using std::ifstream and convert them to your character type. 除非您真正致力于为字符类型uint16_t创建I / O流,否则您可能想使用std::ifstream读取字节并将其转换为字符类型。 Similarly for writing characters. 写字符也一样。 To really create an I/O stream also supporting formatting, you'd need a number of other facets, too (eg, std::ctype<uint16_t> , std::num_punct<uint16_t> ) and you'd need to build a std::locale to contain all of these plus a few which can be instantiated from the standard library's implementation (eg, std::num_get<uint16_t> and std::num_put<uint16_t> ; I think their iterator types are suitable defaulted). 要真正创建还支持格式的I / O流,您还需要其他一些方面(例如std::ctype<uint16_t>std::num_punct<uint16_t> ),并且需要构建一个std::locale包含所有这些内容以及可以从标准库的实现中实例化的一些内容(例如std::num_get<uint16_t>std::num_put<uint16_t> ;我认为它们的迭代器类型适合作为默认值)。

When I try your code, the file is written, but nothing is inside, its size is 0 after closing it. 当我尝试您的代码时,文件已写入,但是里面什么也没有,关闭文件后其大小为0。 When reading from that file, nothing can be read. 从该文件读取时,无法读取任何内容。 What you see in the output is uninitialized garbage. 您在输出中看到的是未初始化的垃圾。

Besides using ofstream/ifstream with default char you should not necessarily rely on read() and write() methods because they do not indicate if they actually write anything. 除了使用带有默认char的ofstream / ifstream之外,您不必依赖于read()write()方法,因为它们不指示它们是否实际写任何东西。 Refer to http://en.cppreference.com/w/cpp/io/basic_ostream/write for details on this. 有关详细信息,请参考http://en.cppreference.com/w/cpp/io/basic_ostream/write Especially this is interesting: 特别是,这很有趣:

This function is an unformatted output function: it begin execution by constructing an object of type sentry, which flushes the tie()'d output buffers if necessary and checks the stream errors. 该函数是未格式化的输出函数:它通过构造一个类型为sendry的对象开始执行,该对象将在必要时刷新tie()的输出缓冲区并检查流错误。 After construction, if the sentry object returns false, the function returns without attempting any output. 构造后,如果哨兵对象返回false,则该函数将返回而不会尝试任何输出。

It is likely that this is why there is not output written to your file because it seems it is not designed to work with any other types than char or similar. 这很可能就是为什么没有将输出写入文件的原因,因为它似乎并未设计为与char或类似类型以外的任何其他类型一起使用。

Update: To see if writing/reading succeed check the fail or bad bit which should have already indicated that something went wrong. 更新:要查看写入/读取是否成功,请检查失败或错误的位,该位应该已经表明出了点问题。

cout << aw.fail() << aw.bad() << "\n";
cout << ax.fail() << ax.bad() << "\n";

Both were set to true, so your real question should have been: why did the call to write() fail? 两者都设置为true,所以您真正的问题应该是:为什么对write()的调用失败?

I suggest reading: http://www.cplusplus.com/articles/DzywvCM9/ 我建议阅读: http : //www.cplusplus.com/articles/DzywvCM9/

Snippets: 片段:

"The problem with these types is that their size is not well defined. int might be 8 bytes on one machine, but only 4 bytes on another. The only one that's consistent is char... which is guaranteed to always be 1 byte." “这些类型的问题是它们的大小定义不正确。int在一台机器上可能是8个字节,而在另一台机器上只有4个字节。唯一一致的是char ...,保证始终是1个字节。 ”

u16 ReadU16(istream& file)
{
  u16 val;
  u8 bytes[2];

  file.read( (char*)bytes, 2 );  // read 2 bytes from the file
  val = bytes[0] | (bytes[1] << 8);  // construct the 16-bit value from those bytes

  return val;
}

void WriteU16(ostream& file, u16 val)
{
  u8 bytes[2];

  // extract the individual bytes from our value
  bytes[0] = (val) & 0xFF;  // low byte
  bytes[1] = (val >> 8) & 0xFF;  // high byte

  // write those bytes to the file
  file.write( (char*)bytes, 2 );
}

You may want to refresh on the "typedef" keyword as well, for defining the guaranteed-#-bits types. 您可能还想刷新“ typedef”关键字,以定义保证的#位类型。 While a little more of a learning curve, Boost and C99 compilers define guaranteed size types as well. 虽然学习曲线要​​多一点,但Boost和C99编译器还定义了保证的大小类型。 I'm not sure about X++0x, but it's too new to be portable. 我不确定X ++ 0x,但是它太新了,无法移植。

You can use char specializations and reinterpret_cast: 您可以使用char专长和reinterpret_cast:

basic_ofstream<char> aw;
...
aw.write( reinterpret_cast<const char*>(i16buf), n2write*sizeof(int16_t) );

basic_ifstream<char> ax;
...
ax.read( reinterpret_cast<char*>(i16buf), n2read*sizeof(int16_t) );

The "sizeof(int16_t)" is for the edge cases where sizeof(int16_t)==1 (eg DSP processors) “ sizeof(int16_t)”适用于sizeof(int16_t)== 1的极端情况(例如DSP处理器)

Of course, if you need to read/write in a specific byte order, then you need endian conversion functions. 当然,如果您需要以特定的字节顺序进行读/写,则需要字节序转换功能。 Note, there is no standard compile-time way of determining endianness. 注意,没有确定字节序的标准编译时方法。

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

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