过去某个时间点无法读取二进制文件
Can't read binary file past some point
我需要解析几个包含 2 字节整数值的二进制文件。因为我最近发现我不知道 C++ 中的流是如何工作的,所以我决定尝试它们而不是好的 ole fopen(); fread()
。所以我有这个功能:
void work( string filename )
{
ifstream f( filename );
if ( !f.is_open() )
throw exception( ("File not found: "+filename).c_str() );
//first 128 bytes are header that shouldn't be parsed
f.seekg( 0, f.end );
uint64_t length = f.tellg();
f.seekg( 128, f.beg );
if ( !f.good() )
throw exception( "Couldn't skip the 128byte header" );
length -= 128;
uint8_t buf[4];
vector<int> first, second;
size_t v = 0;
int a = -1;
int b = -1;
while ( !f.eof() )
{
f.read( reinterpret_cast<char*>(buf), 4 );
if ( !f.good() )
{
cerr << "Couldn't read two 2byte values: read " << f.gcount() << "/4 bytes" << endl
<< "Bytes parsed: " << v << "/" << length << endl
<< "last 4 bytes: "
<< hex << +buf[0] << " " << +buf[1] << " | " << +buf[2] << " " << +buf[3] << endl;
string s;
if ( f.bad() )
s = "BAD";
else if ( f.fail() )
s = "FAIL";
else
s = "WAT";
throw exception( s.c_str() );
}
//only first 10 bits of values actually matter
a = get10bit( buf[0], buf[1] );
first.push_back( a );
b = get10bit( buf[2], buf[3] );
second.push_back( b );
v += 4;
}
doStuff( first, second );
}
但是由于某种原因,循环在只读取文件的一部分后停止,所以我得到下一个输出:
Couldn't read two 2byte values: read 0/4 bytes
Bytes parsed: 88/1000000
last 4 bytes: 57 f0 | 3d 0
Exception: FAIL
我以为问题是我对流的使用不正确,所以我尝试切换到fread()
,但结果是一样的。然后我在其他几个文件上测试了该程序的两个版本,猜测这个文件有问题......但令我惊讶的是,f.fail()
最终触发了我试图解析的任何文件!但是,每个文件成功解析的字节数不同。
按照我父亲的建议,我随后尝试读取更大的数据块(甚至整个文件)而不是多个 4 字节部分,但这也无济于事。现在我完全没主意了。
以防万一:我的原始文件的内容(十六进制),跳过 header。我用粗体突出显示了最后一对正确读取的值。
E7 FF 4C 00 FD FF 01 00 2A 00 ED FF 0A 00 43 00
12 00 26 00 53 00 DB FF F3 FF 0C 00 EC FF 50 00
6E 00 10 00 37 00 D1 FF FA FF 0D 00 29 00 44 00
4E 00 2F 00 15 00 1C 00 9F FF 36 00 35 FE ED FF
E4 FB C4 FF C1 F4 23 00 E6 EA 39 00 73 EB D5 FF
99 EF DF FF 57 F0 3D 00 1A F3 2C 00 97 F5 E7 EF
您正在以文本模式打开文件,而您应该以二进制模式打开它。在文本模式下,符号 ^Z
(ASCII 26 = 0x1A) 是 EOF(文件结束)控制代码。
将代码更改为:
ifstream f( filename, ifstream::binary );
我需要解析几个包含 2 字节整数值的二进制文件。因为我最近发现我不知道 C++ 中的流是如何工作的,所以我决定尝试它们而不是好的 ole fopen(); fread()
。所以我有这个功能:
void work( string filename )
{
ifstream f( filename );
if ( !f.is_open() )
throw exception( ("File not found: "+filename).c_str() );
//first 128 bytes are header that shouldn't be parsed
f.seekg( 0, f.end );
uint64_t length = f.tellg();
f.seekg( 128, f.beg );
if ( !f.good() )
throw exception( "Couldn't skip the 128byte header" );
length -= 128;
uint8_t buf[4];
vector<int> first, second;
size_t v = 0;
int a = -1;
int b = -1;
while ( !f.eof() )
{
f.read( reinterpret_cast<char*>(buf), 4 );
if ( !f.good() )
{
cerr << "Couldn't read two 2byte values: read " << f.gcount() << "/4 bytes" << endl
<< "Bytes parsed: " << v << "/" << length << endl
<< "last 4 bytes: "
<< hex << +buf[0] << " " << +buf[1] << " | " << +buf[2] << " " << +buf[3] << endl;
string s;
if ( f.bad() )
s = "BAD";
else if ( f.fail() )
s = "FAIL";
else
s = "WAT";
throw exception( s.c_str() );
}
//only first 10 bits of values actually matter
a = get10bit( buf[0], buf[1] );
first.push_back( a );
b = get10bit( buf[2], buf[3] );
second.push_back( b );
v += 4;
}
doStuff( first, second );
}
但是由于某种原因,循环在只读取文件的一部分后停止,所以我得到下一个输出:
Couldn't read two 2byte values: read 0/4 bytes
Bytes parsed: 88/1000000
last 4 bytes: 57 f0 | 3d 0
Exception: FAIL
我以为问题是我对流的使用不正确,所以我尝试切换到fread()
,但结果是一样的。然后我在其他几个文件上测试了该程序的两个版本,猜测这个文件有问题......但令我惊讶的是,f.fail()
最终触发了我试图解析的任何文件!但是,每个文件成功解析的字节数不同。
按照我父亲的建议,我随后尝试读取更大的数据块(甚至整个文件)而不是多个 4 字节部分,但这也无济于事。现在我完全没主意了。
以防万一:我的原始文件的内容(十六进制),跳过 header。我用粗体突出显示了最后一对正确读取的值。
E7 FF 4C 00 FD FF 01 00 2A 00 ED FF 0A 00 43 00
12 00 26 00 53 00 DB FF F3 FF 0C 00 EC FF 50 00
6E 00 10 00 37 00 D1 FF FA FF 0D 00 29 00 44 00
4E 00 2F 00 15 00 1C 00 9F FF 36 00 35 FE ED FF
E4 FB C4 FF C1 F4 23 00 E6 EA 39 00 73 EB D5 FF
99 EF DF FF 57 F0 3D 00 1A F3 2C 00 97 F5 E7 EF
您正在以文本模式打开文件,而您应该以二进制模式打开它。在文本模式下,符号 ^Z
(ASCII 26 = 0x1A) 是 EOF(文件结束)控制代码。
将代码更改为:
ifstream f( filename, ifstream::binary );