读取二进制数据寻找十六进制序列
Read Binary Data looking for Sequence of Hex
我有一个二进制文件可供读取,文件内部是非固定长度的数据,但它们确实有开始和停止序列。
起始序列为 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<vector<char>>
?
下面是我逐字节进行的迭代。
for (vector<char>::iterator it = buff.begin(); it != buff.end(); ++it)
{
if (*it == 0x1B)
{
// found ESC char
}
}
我如何设置从二进制文件读取、写入字节直到停止序列然后重复文件的其余部分?
我写了一些示例代码来扫描给定的字节向量并将在 start/stop 序列之间找到的字节运行存储到字节向量的向量中。
还没有真正测试过,但确实可以编译:-)
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;
}
}
}
我觉得格式错误。如果您的数据包含 begin/end 序列怎么办?你如何编码它们?
你太依赖stl
了。您不必将输入读入 vector
。编写一个函数,使用 istream::get
和 istream::unget
从流中提取标记。这可能是您必须编写的最复杂的函数。您的函数必须 return 的标记是:
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;
}
你的 reader 应该是这样的:
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 - 没有保证。
我有一个二进制文件可供读取,文件内部是非固定长度的数据,但它们确实有开始和停止序列。
起始序列为 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<vector<char>>
?
下面是我逐字节进行的迭代。
for (vector<char>::iterator it = buff.begin(); it != buff.end(); ++it)
{
if (*it == 0x1B)
{
// found ESC char
}
}
我如何设置从二进制文件读取、写入字节直到停止序列然后重复文件的其余部分?
我写了一些示例代码来扫描给定的字节向量并将在 start/stop 序列之间找到的字节运行存储到字节向量的向量中。
还没有真正测试过,但确实可以编译:-)
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;
}
}
}
我觉得格式错误。如果您的数据包含 begin/end 序列怎么办?你如何编码它们?
你太依赖stl
了。您不必将输入读入 vector
。编写一个函数,使用 istream::get
和 istream::unget
从流中提取标记。这可能是您必须编写的最复杂的函数。您的函数必须 return 的标记是:
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;
}
你的 reader 应该是这样的:
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 - 没有保证。