C ++中的二进制文件写入问题

时间:2011-03-23 20:56:56

标签: c++ visual-c++

这是我创建二进制文件的函数

void writefile()
{
    ofstream myfile ("data.abc", ios::out | ios::binary);
    streamoff offset = 1;
    if(myfile.is_open())
    {
        char c='A';
        myfile.write(&c, offset );
        c='B';
        myfile.write(&c, offset );
        c='C';
        myfile.write(&c,offset);
        myfile.write(StartAddr,streamoff (16) );
        myfile.close();
    }
     else
         cout << "Some error" << endl ;
}

StartAddr的值为1000,因此预期的输出文件为: A B C 1000 NUL NUL NUL

然而,奇怪的是我的输出文件附加了这个:data.abc

所以最后的结果是:A B C 1000 NUL NUL NUL data.abc

请帮我解决这个问题。怎么处理这个?为什么这种奇怪的行为?

3 个答案:

答案 0 :(得分:2)

我建议您退出二进制写作并以文本格式编写数据。您已经遇到了编写数据的一些问题。您在阅读数据和可移植性方面仍然存在问题。如果你继续这条路线,会有更多的痛苦。

使用文字表示。为简单起见,您可以为每行添加一个字段,并使用std::getline来读取它。文本表示允许您轻松地在任何文本编辑器中查看数据。尝试使用{{1}查看二进制文件!

哦,但是二进制数据太快了,文件占用的空间更少。你已经浪费了足够的时间和金钱,而不是使用二进制数据。计算机的速度和巨大的内存容量(磁盘和RAM)使二进制表示成为过去(除非在极端情况下)。

作为一种学习工具,请继续使用二进制文件。为了便于开发和快速安排(IOW,尽早完成),请使用文本表示。

搜索Stack Overflow以获取“C ++微优化”的理由。

答案 1 :(得分:1)

此代码存在几个问题。

对于初学者,如果要在流中编写单个字符,则不需要使用ostream :: write。相反,只需使用ostream :: put,如下所示:

myfile.put('A');

其次,如果要将字符串写入文件流,只需使用流插入运算符:

myfile << StartAddr;

即使在二进制模式下,这也是非常安全的。

至于您报告的特定问题,我认为问题是您正在尝试写出长度为4的字符串(StartAddr),但您已经告诉流写出16个字节。这意味着你要写出字符串内容的四个字节,然后是空终止符,然后是缓冲区之后内存中发生的9个字节。在你的情况下,这是两个空字节,然后是你之后看到的无意义的文本。要解决此问题,请更改代码以写入更少的字节,或者如果StartAddr是字符串,则只需使用&lt;&lt;。

进行编写。

答案 2 :(得分:0)

使用行myfile.write(StartAddr,streamoff (16) );,您指示myfile对象将16个字节写入从地址StartAddr开始的流。想象一下,StartAddr是一个16字节的数组:

char StartAddr[16] = "1000\0\0\0data.b32\0";
myfile.write(StartAddr, sizeof(StartAddr));

会生成您看到的输出。在没有看到StartAddr的声明/定义的情况下,我无法肯定地说,但是看起来你正在写出一个5字节的nul终止字符串"1000",然后是在StartAddr之后的下一个11字节中发生的任何事情。在这种情况下,它出现了几个nul字节后跟常量nul终止字符串"data.b32"(编译器必须放在内存中的某个地方)跟随StartAddr。

无论如何,很明显你覆盖了一个缓冲区。

如果您尝试将16位整数类型写入流,则有两个选项,这两个选项都基于一个字节中通常有8位的事实。 “最干净”的是:

char x = (StartAddr & 0xFF);
myfile.write(x);
x = (StartAddr >> 8);
myfile.write(x);

这假设StartAddr是一个16位整数类型,并没有考虑可能发生的任何转换(例如可能将值10 [换行]转换为回车/换行序列)。

或者,您可以编写如下内容:

myfile.write(reinterpret_cast<char*>(&StartAddr), sizeof(StartAddr));