【问题标题】:Read Binary Data looking for Sequence of Hex读取二进制数据以查找十六进制序列
【发布时间】:2018-11-28 23:58:03
【问题描述】:

我有一个二进制文件要读取,文件内部是非固定长度的数据,但它们确实有开始和停止序列。

起始序列为 0x1B 0x5B 0x30 0x48
停止序列为 0x1b 0x5B 0x31 0x48

这个特定的文件确实有 28 个条目,想想有多少条目可能不同。

我已经将二进制文件读入到文件大小的向量

ifstream datafile("myfile.bin", ios_base::in|ios_base::binary);
vector<char> buff;
int size = datafile.tellg();
buff.resize(size);

datafile.read(buff.data(), size);

现在我尝试逐字节迭代向量(因为这就是它存储在向量中的方式,对吧?但这不是我想要的。

阅读将数据写入另一个(临时)变量的向量然后在我看到停止序列时停止写入它会很好。然后继续处理向量的其余部分,写入另一个变量,直到看到下一个停止序列等。就像写入vector&lt;vector&lt;char&gt;&gt; ?

以下是我逐字节进行的迭代。

for (vector<char>::iterator it = buff.begin(); it != buff.end(); ++it)
{
  if (*it == 0x1B)
  {
    // found ESC char
  }
}

我如何设置从二进制文件读取,写入字节直到停止序列,然后重复文件的其余部分?

【问题讨论】:

  • 如果我理解正确,您希望将整个文件读入内存,然后将每组开始/结束标记之间的字节提取到它们自己的缓冲区中?听起来很简单,你在哪一部分遇到了麻烦?

标签: c++ linux binary byte ifstream


【解决方案1】:

我编写了一些示例代码,它扫描给定的字节向量并将在开始/停止序列之间找到的字节运行存储到字节向量向量中。

还没有真正测试过它,但它确实可以编译:-)

void findSequences( vector< char >& buff, vector< vector< char > > *dataRuns )
{
  char startSequence[] = { 0x1B, 0x5B, 0x30, 0x48 };
  char endSequence[] = { 0x1b, 0x5B, 0x31, 0x48 };

  bool findingStart = true;

  vector< char >::iterator it = buff.begin();
  vector< char >::iterator itEnd = buff.end();
  while ( it != itEnd )
  {
    vector< char >::iterator findIt;
    if ( findingStart )
      findIt = search( it, itEnd, startSequence, startSequence + 4 );
    else
      findIt = search( it, itEnd, endSequence, endSequence + 4 );

    if ( findIt != itEnd )
    {
      if ( findingStart )
      {
        it = findIt + 4;
        findingStart = false;
      }
      else
      {
        dataRuns->push_back( vector< char >( it, findIt ) );
        it = findIt + 4;
        findingStart = true;
      }
    }
    else
    {
      // failed to find a start or stop sequence

      break;
    }
  }
}

【讨论】:

  • 这很好用。我稍微修改了它,因为我仍然需要向量中的开始/结束序列。谢谢!!
【解决方案2】:

格式在我看来错误。如果您的数据包含开始/结束序列怎么办?你如何编码它们?

你太依赖stl。您不必将输入读入vector。编写一个函数,使用istream::getistream::unget 从流中提取令牌。这可能是您必须编写的最复杂的函数。您的函数必须返回的标记是:

  • data-begin:你的开始转义序列。
  • data:一个数据字节。
  • data-end:你的结束转义序列。
  • done:流结束。

此功能将使数据提取变得简单:

bool reader_t::get_data( std::vector< char >& d ) // returns false on end of stream
{
  d.clear();

  get_token();

  if ( _tok == done )
    return false; // end of stream

  if ( _tok != data_beg )
    throw "data begin expected";

  while ( get_token() == data )
    d.push_back( _c );

  if ( _tok != data_end )
    throw "data end expected";

  return true;
}

处理整个流也很简单:

int main()
{
  std::ifstream is { R"(d:\temp\test.bin)" };
  if ( !is )
    return 0;

  reader_t r { is };
  std::vector< char > v;
  try
  {
    while ( r.get_data( v ) )
      ;// process v;
  }
  catch ( const char* e )
  {
    std::cout << e;
  }

  return 0;
}

您的阅读器应该是这样的:

class reader_t
{
  std::istream& _is;

  enum token_t
  {
    data_beg,
    data_end,
    data,
    done
  };

  token_t _tok;
  char _c;

  token_t get_token();

public:

  reader_t( std::istream& a_is );
  bool get_data( std::vector< char >& d ) // returns false on end of stream
};

这是匆忙写的demo - 不提供任何保证。

【讨论】:

  • 我希望开始/结束序列不会成为数据本身的一部分,但它也不是我正在使用的协议。感谢代码示例的解释!
猜你喜欢
  • 2020-10-25
  • 2020-05-09
  • 2014-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
相关资源
最近更新 更多