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

时间:2012-10-09 19:09:18

标签: c++ stl iostream widechar

我想将非Unicode,16位字写入文件,稍后再读回。我知道通过一些字节操作,我可以使用charfstream::read()fstream::write()模式下执行此操作。直接使用16位字需要做什么?

例如,似乎我应该能够执行以下操作:

 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输出:

d 0

Vc ++ 10输出:

CCCC CCCC

我也尝试直接使用std::basic_filebuf<uint16_t>并得到相同的结果。为什么呢?

4 个答案:

答案 0 :(得分:6)

我真的很惊讶你让溪流被实例化以完成任何阅读!结果可能是实现定义的(即,您可能会发现编译器文档中描述的行为),但可能只是没有指定(虽然不是很明确)。我不认为流类需要立即支持除charwchar_t以外的其他类型的实例化,即,用户不提供至少一些方面。

标准流类是字符类型上的模板,但对于任何不受支持的类型都不容易实例化。至少,您需要在字节外部表示和内部表示之间实现合适的std::codecvt<int16_t, char, std::mbstate_t>方面转换。从它的外观来看,你尝试的两个系统为它们的默认实现做了不同的选择。

std::codecvt<internT, externT, stateT>是用于在字符的外部表示和字符的内部表示之间进行转换的方面。流只需要支持char,它被视为表示字节作为外部类型externT。内部字符类型internT可以是任何整数类型,但转换需要通过实现代码转换方面来定义。如果我没记错的话,流也可以假设状态类型stateTstd::mbstate_t(这实际上有点问题,因为没有为这种类型定义接口!)。

除非您真的致力于为字符类型uint16_t创建I / O流,否则您可能希望使用std::ifstream读取字节并将它们转换为您的字符类型。类似地写字符。要真正创建支持格式化的I / O流,您还需要许多其他方面(例如std::ctype<uint16_t>std::num_punct<uint16_t>)并且您需要构建一个std::locale包含所有这些以及可以从标准库的实现中实例化的一些(例如,std::num_get<uint16_t>std::num_put<uint16_t>;我认为它们的迭代器类型是合适的默认值)

答案 1 :(得分:2)

当我尝试你的代码时,文件被写入,但内部没有任何内容,关闭后它的大小为0。从该文件中读取时,无法读取任何内容。你在输出中看到的是未初始化的垃圾。

除了使用带有默认字符的ofstream / ifstream之外,你不一定要依赖read()write()方法,因为它们并不表示它们是否实际写了任何东西。有关详细信息,请参阅http://en.cppreference.com/w/cpp/io/basic_ostream/write。特别是这很有趣:

  

此函数是未格式化的输出函数:它开始执行   构造一个类型为sentry的对象,它会刷新tie()'d   必要时输出缓冲区并检查流错误。后   构造,如果sentry对象返回false,则函数返回   没有尝试任何输出。

这可能就是为什么没有输出写入您的文件的原因,因为它似乎不适用于除char或类似之外的任何其他类型。

更新:查看写入/读取是否成功检查应该已经指示出错的故障或坏位。

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

两者都设置为true,所以你真正的问题应该是:为什么调用write()会失败?

答案 2 :(得分:1)

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

代码段:

  

“这些类型的问题在于它们的大小没有明确定义。   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 );
}

您可能还想刷新“typedef”关键字,以定义保证 - # - 位类型。虽然更多的学习曲线,Boost和C99编译器也定义了有保证的大小类型。我不确定X ++ 0x,但它太新了,无法移植。

答案 3 :(得分:1)

您可以使用char specializations和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) );

“sizeof(int16_t)”适用于sizeof(int16_t)== 1的边缘情况(例如DSP处理器)

当然,如果您需要以特定的字节顺序读/写,那么您需要字节序转换功能。注意,没有标准的编译时确定字节序的方法。