【问题标题】:trouble reading binary data读取二进制数据有问题
【发布时间】:2013-04-16 15:28:23
【问题描述】:

读者和作者

#include<string>
#include<fstream>
#include<memory>

class BinarySearchFile{

     BinarySearchFile::BinarySearchFile(std::string file_name){

     // concatenate extension to fileName
     file_name += ".dat";

     // form complete table data filename
     data_file_name = file_name;

     // create or reopen table data file for reading and writing
     binary_search_file.open(data_file_name, std::ios::binary);  // create file

     if(!binary_search_file.is_open()){

          binary_search_file.clear();
          binary_search_file.open(data_file_name, std::ios::out | std::ios::binary);
          binary_search_file.close();
          binary_search_file.open(data_file_name), std::ios::out | std::ios::in | std::ios::binary | std::ios::ate;
     }

    std::fstream binary_search_file;

    void BinarySearchFile::writeT(std::string attribute){

        if(binary_search_file){
            binary_search_file.write(reinterpret_cast<char *>(&attribute), attribute.length() * 2);
        }
    }

    std::string BinarySearchFile::readT(long filePointerLocation, long sizeOfData) 
    {
        if(binary_search_file){
           std::string data;
           data.resize(sizeOfData);
           binary_search_file.seekp(filePointerLocation);
           binary_search_file.seekg(filePointerLocation);
           binary_search_file.read(&data[0], sizeOfData);
           return data; 
    }
};

读者来电

while (true){
    std::unique_ptr<BinarySearchFile> data_file(new BinarySearchFile("classroom.dat"));

    std::string attribute_value = data_file->read_data(0, 20);

}

作者来电

    data_file->write_data("packard   ");

writer总共写入50个字节

"packard   101       500  "

阅读器要读取第一个20 bytes,结果是“X packard X”,其中X 表示一些格式错误的数据字节。为什么以 x 字节数读回的数据损坏?

【问题讨论】:

  • 文件是字节流。如果要写入文件,则需要一个字节流来写入该文件,该文件遵循您想要的任何文件格式。你有文件格式吗?您是否以该格式创建字节流?您希望这会变魔术。
  • 你有文件格式吗?二进制!您是否以该格式创建字节流?我相信我这样做了,但显然是错误的。
  • 如果有文件格式,第一个字节是什么意思?将特定信息放入您写入文件的数据的第一个字节的代码在哪里?
  • @Mushy Binary 不是一种文件格式。这只是一个粗略的指示,表明您使用的格式不限于可打印字符。
  • 是的,我有一个使用 char 作为两字节类型的文件格式,这将使写入“packard” 20 字节。我使用std::fstream::write() 写入这20 个字节,然后使用std::fstream::read() 读取这20 个字节。

标签: c++ fstream


【解决方案1】:

您不能通过将数据的地址转换为char* 来简单地写出数据并希望得到任何有用的东西。您必须定义要使用的二进制格式并实现它。对于std::string,这可能意味着以某种格式输出长度,然后是实际数据。或者在需要固定长度字段的情况下,使用std::string::resize 将字符串(或字符串的副本)强制为该长度,然后使用std::string::data() 输出该长度以获取您的char const*

当然,阅读也是类似的。您将数据读入std::vector&lt;char&gt;(或对于固定长度字段,char[]),然后解析它。

【讨论】:

  • 好的,谢谢。我修改了作者如下:attribute.resize(attribute.length() * 2);const char *write_this = attribute.data();binary_search_file.write(write_this, attribute.length());和读者如下:char data[20];binary_search_file.read(data, sizeOfData);,我得到了我想要的,但需要修剪它以便实际数据是正确的
  • @Mushy 这应该几乎可以工作。但是,我不认为长度 * 2 的 resize 可以满足您的要求;它只是将带有 '\0' 的 attribute.length() 字节添加到字符串的末尾。为什么每个字符要 2 个字节,第二个字节代表什么。如果您想要 UTF-16,并且输入字符串是 UTF-8,则需要显式转码,最终长度将取决于字符串的内容。 (当然,其他人的做法正好相反:内部使用 UTF-16 或 UTF-32,文件和网络中使用 UTF-8。)
  • 我想要一个两字节字符,因为我正在将使用两字节字符的 Java 程序转换为字符为一字节的 c++。为了在转换中保持有序格式并使验证更容易,我选择使用两字节字符。如果我没有正确表示一个两字节的字符,请在必要时通过转码或转换正确地执行它以保持我想要的格式。
  • @Mushy 好的。 Java 的外部格式是 UTF-16BE。 如果您的编码是 ISO 8859-1 或纯 ASCII,那么您可以简单地将最高字节设置为 0;否则,您将不得不使用更经典的技术进行转码。有很多方法可以做到这一点,但最简单的方法是创建一个std::vector&lt;char&gt;,然后循环输入,插入第一个'0',然后将字符插入向量,最后写入v.data()(如果你有C ++11) 或&amp;v[0] 到输出。 (或者您可以直接写入输出:dest.put() 每个字节。)
【解决方案2】:

binary_search_file.write(reinterpret_cast&lt;char *&gt;(&amp;attribute), attribute.length() * 2);
std::string 转换为char* 是不正确的,如果需要char*,则必须使用attribute.c_str()
std::string 除了字符串指针还包含其他数据成员,例如分配器,您的代码会将所有这些数据写入文件。此外,我看不出有任何理由将字符串长度乘以 2。如果你想输出终止零,+1 是有意义的。

【讨论】:

  • 任何时候你需要reinterpret_cast,除非你在做非常底层的工作(例如实现malloc),你应该怀疑。
  • @JamesKanze 在 c_str() 的情况下,不需要重新解释演员表,因为手头会有 char*。还是我错过了什么?
  • c_str() 的情况是不需要reinterpret_cast:-) 的情况。您需要在文件中使用某种方法来恢复长度。
  • @JamesKanze 终端零还不够吗?
  • 它可能,如果你真的写它。这取决于格式和阅读方式。
猜你喜欢
  • 2013-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
相关资源
最近更新 更多