【问题标题】:Reading\Writing Structured Binary File in C++在 C++ 中读\写结构化二进制文件
【发布时间】:2012-08-05 12:06:29
【问题描述】:

我想读\写一个具有以下结构的二进制文件:

文件由“记录”组成。每个“RECORD”的结构如下:我以第一条记录为例

  • (红色)起始字节:0x5A(始终为 1 字节,固定值 0x5A)
  • (绿色)LENGTH 个字节:0x00 0x16(总是 2 个字节,值可以改变 从“0x00 0x02”到“0xFF 0xFF”)
  • (蓝色) CONTENT:由十进制值表示的字节数 LENGTH 字段减 2。

在这种情况下,LENGHT 字段值为 22(0x00 0x16 转换为十进制),因此 CONTENT 将包含 20 (22 - 2) 个字节。 我的目标是逐条读取每条记录,并将其写入输出文件。其实我有一个读函数和写函数(一些伪代码):

private void Read(BinaryReader binaryReader, BinaryWriter binaryWriter)
{
    byte START = 0x5A;
    int decimalLenght = 0;
    byte[] content = null;
    byte[] length = new byte[2];

    while (binaryReader.PeekChar() != -1)
    {
        //Check the first byte which should be equals to 0x5A
        if (binaryReader.ReadByte() != START)
        {
            throw new Exception("0x5A Expected");
        }

        //Extract the length field value
        length = binaryReader.ReadBytes(2);

        //Convert the length field to decimal
        int decimalLenght = GetLength(length);

        //Extract the content field value
        content = binaryReader.ReadBytes(decimalLenght - 2);

        //DO WORK
        //modifying the content

        //Writing the record
        Write(binaryWriter, content, length, START);
    }
}

private void Write(BinaryWriter binaryWriter, byte[] content, byte[] length, byte START)
{
    binaryWriter.Write(START);
    binaryWriter.Write(length);
    binaryWriter.Write(content);   
}

如您所见,我已经为 C# 编写了它,但我真的不知道如何用 C++ 编写它。 有人可以指出我正确的方向吗?

【问题讨论】:

    标签: c++ visual-studio-2010 io binaryfiles


    【解决方案1】:

    您需要使用std::ifstream 并在binary mode (std::ios_base::binary) 中打开文件。

    peek 非常相似,但如果无法提取字符,则返回 eof 而不是 -1read 将使您能够将给定数量的字节读入一个值。请注意,您熟悉的某些类型(bytetype[])在 C++ 中不存在或工作方式不同。后者可以使用std::vector,但需要自己定义byte

    【讨论】:

      【解决方案2】:

      我想我会按照这个顺序做点什么:

      struct record { 
          static const int start = '\x5a';
          std::vector<char> data; // you might prefer unsigned char.
      };
      
      std::istream &operator>>(std::istream &is, record &r) { 
          char ch;
          short len;
      
          is.get(ch);
          verify(ch == record::start);
          is.read((char *)&len, sizeof(len));
          r.data.resize(len);
          is.read(&r.data[0], len);
          return is;
      }
      
      std::ostream &operator<<(std::ostream &os, record const &r) { 
          os << record::start;
          short len = (short)r.data.size();
          os.write((char *)&len, sizeof(len));
          os.write(&r.data[0], len);
          return os;
      }
      

      要处理您在Read 中显示的记录文件(顺便说一句,读取、处理和写入数据的东西的名字很差),让我们首先定义一个函子来处理文件中的单个记录:

      class process_record { 
          record operator()(record r) { 
              // code to process a single record goes here
              // it will take one record as input, and return the processed record.
          }
      }
      

      然后,为了处理文件,我们将使用如下代码:

      std::transform(std::istream_iterator<record>(infile),
                     std::istream_iterator<record>(),
                     std::ostream_iterator<record>(outfile, ""),
                     process_record());
      

      [注意:为了简洁起见,我在这里使用了 C 风格的强制转换,但在实际代码中我可能会改用 static_casts。]

      【讨论】:

        【解决方案3】:

        好的,根据你的回答我做了一些实验:

        string sFile = "C:\Test.bin";
        static const int START_BYTE = '\x5a';
        char tempByte;
        
        ifstream inputFile (sFile, ios::in);
        inputFile.open( sFile, ios::binary );
        
        while (!inputFile.eof()) 
        {
            inputFile.get(temptByte);
        
            cout << "Value of Byte " << hex << static_cast<int>(tempByte) << " hexadecimal" << endl;
        }
        

        但是,输出始终显示为:ffffffcc,或者如果未转换为 -52。

        如果我做对了,我的代码应该一次读取一个字节的文件,并打印出字节十六进制值。我错了吗?

        【讨论】:

          【解决方案4】:

          感谢你们,这就是我能够开发的解决方案:

          // TestCPP003.cpp : Defines the entry point for the console application.
          //
          
          #include "stdafx.h"
          
          #include "boost\program_options.hpp"
          namespace po = boost::program_options;
          
          #include "Util.h"
          
          using namespace std;
          
          int main(int argc, char* argv[])
          {
              po::options_description desc("Allowed options");
          
              desc.add_options()
                  ("h", "produce help message")
                  ("i", po::value<string>(), "input file")
                  ("o", po::value<string>(), "output file");
          
              po::variables_map vm;
              po::store(po::parse_command_line(argc, argv, desc), vm);
          
              if (vm.count("h"))
              {
                  cout << desc << endl;
                  return 0;
              }
          
              po::notify(vm);
          
              if (vm.count("i"))
              {
                  cout << vm["i"].as<string>() << "\n";
              }
          
              string sInputFile = vm["i"].as<string>();
          
              if (fileExists(sInputFile.c_str()))
              {
                  cout << "file exists: <" <<  sInputFile << ">" << endl;
              }
              else
              {
                  cout << "file not exists: <" <<  sInputFile << ">" << endl;
                  cout << "RETURN CODE: 8" << endl;
                  return 8;
              }
          
              string sOutputFile = vm["o"].as<string>();
          
              static const int START_BYTE = '\x5a';
              static const int AFP_RECORD_HEADER_SIZE = 1;
              static const int AFP_RECORD_LENGTH_SIZE = 2;    
              char * afpHeaderBlock = new char[1];
              char * afpLengthBlock;
              unsigned int afpRecordLength = 0;
              char * afpContentBlock;
          
              ifstream inputStream(sInputFile, ios::in|ios::binary);
              ofstream outputStream(sOutputFile, ios::out|ios::binary);
          
              if (inputStream.is_open() && outputStream.is_open())
              {
                  while (inputStream.read(afpHeaderBlock, AFP_RECORD_HEADER_SIZE)) 
                  {           
                      //cout << ToHex(string(afpHeaderBlock, AFP_RECORD_HEADER_SIZE), true) << endl;
          
                      if (START_BYTE == afpHeaderBlock[0])
                      {
                          cout << "0x5A Found!" << endl;
                      }
                      else
                      {
                          cout << "0x5A not Found! - AFP Error" << endl;
                      }
          
                      outputStream.write(afpHeaderBlock,  AFP_RECORD_HEADER_SIZE);
          
                      afpLengthBlock = new char[AFP_RECORD_LENGTH_SIZE];
                      afpRecordLength = 0;
          
                      inputStream.read(afpLengthBlock, AFP_RECORD_LENGTH_SIZE);
          
                      //cout << ToHex(string(afpLengthBlock, AFP_RECORD_LENGTH_SIZE), true) << endl;
          
                      afpRecordLength = (afpRecordLength << 8) + static_cast<const unsigned char&>(afpLengthBlock[0]);
                      afpRecordLength = (afpRecordLength << 8) + static_cast<const unsigned char&>(afpLengthBlock[1]);
          
                      //cout << "AFP Record Length: " << afpRecordLength << endl;
          
                      outputStream.write(afpLengthBlock,  AFP_RECORD_LENGTH_SIZE);
          
                      afpContentBlock = new char[afpRecordLength - AFP_RECORD_LENGTH_SIZE];
          
                      inputStream.read (afpContentBlock, afpRecordLength - AFP_RECORD_LENGTH_SIZE);
          
                      outputStream.write(afpContentBlock,  afpRecordLength - AFP_RECORD_LENGTH_SIZE);
                  }
          
                  inputStream.close();
                  outputStream.flush();
                  outputStream.close();
              }
          
              cout << "RETURN CODE: 0" << endl;
              return 0;
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-08
            • 1970-01-01
            相关资源
            最近更新 更多