我从c ++开始,我需要读取二进制文件。
我知道文件的结构,即每个文件行由:
组成'double';'int8';'float32';'float32';'float32';'float32';'float32';'float32';'int8';'float32';'float32';'float32';'float32';'int8';'float32'
或字节数:
8 1 4 4 4 4 4 4 1 4 4 4 4 1 4
我制作了一些代码但过时了...... 这是代码:
void test1 () {
const char *filePath = "C:\20110527_phantom19.elm2";
double *doub;
int *in;
float *fl;
FILE *file = NULL;
unsigned char buffer;
if ((file = fopen(filePath, "rb")) == NULL)
cout << "Could not open specified file" << endl;
else
cout << "File opened successfully" << endl;
// Get the size of the file in bytes
long fileSize = getFileSize(file);
cout << "Tamanho do ficheiro: " << fileSize;
cout << "\n";
// Allocate space in the buffer for the whole file
doub = new double[1];
in = new int[1];
fl = new float[1];
// Read the file in to the buffer
//fread(fileBuf, fileSize, 1, file);
//fscanf(file, "%g %d %g", doub[0],in[0],fl[0]);
fread(doub, 8, 1, file);
//cout << doub[0]<< " ";
fseek (file ,8, SEEK_SET);
fread(&buffer,1,1,file);
//printf("%d ",buffer);
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(&buffer,1,1,file);
//printf("%d ",buffer);
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(fl,4,1,file);
//cout << fl[0]<< " ";
fread(&buffer,1,1,file);
//printf("%d ",buffer);
fread(fl,4,1,file);
//cout << fl[0]<< "\n";
cin.get();
//delete[]fileBuf;
fclose(file);
}
如何以有效的方式改变它?
答案 0 :(得分:2)
如果您可以使用自定义格式轻松阅读整个结构并让字段自动填充正确的值,会出现什么问题?
struct MyDataFormat {
double d;
int8 i1;
float32 f[6];
..
};
MyDataFormat buffer;
fread(&buffer, sizeof(MyDataFormat), 1, file);
答案 1 :(得分:1)
如果每一行都是相同的格式,我可能会一次读取一行到缓冲区然后有一个函数将该缓冲区分成单独的元素 - 更容易理解,更容易测试,适用于更大的文件,是可以更有效地做更少的阅读。
答案 2 :(得分:1)
除了文件的“结构”之外,我们还需要知道格式
所涉及的数据类型,以及“line”的含义,如果是格式
不是文本格式。但是,一般情况下,你将1)必须阅读
适当大小的块,然后从中提取每个值,
根据指定的格式。对于整数值,它是公平的
易于使用移位提取无符号整数值; for int8
,in
事实上,你只需要读取字节。对于大多数机器,只需铸造
无符号整数将进入相应大小的有符号类型
工作,虽然明确无法保证;如果是unsigned char
如果大于CHAR_MAX
,则必须将其缩小才能得到
适当的价值:-(UCHAR_MAX+1 - value)
之类的东西应该这样做
技巧(对于char
s - 对于较大的类型,您还必须担心
UINT_MAX+1
将溢出的事实。
如果外部格式是IEEE,那也是你的机器 使用(Windows和Unix机器的常见情况,但很少见 对于大型机),那么你可以读取无符号的4或8字节整数 (再次,使用轮班),并输入双关语,如:
uint64_t
get64BitUInt( char const* buffer )
{
return reinterpret_cast<double>(
((buffer[0] << 52) & 0xFF)
| ((buffer[1] << 48) & 0xFF)
| ((buffer[2] << 40) & 0xFF)
| ((buffer[3] << 32) & 0xFF)
| ((buffer[4] << 24) & 0xFF)
| ((buffer[5] << 16) & 0xFF)
| ((buffer[6] << 8) & 0xFF)
| ((buffer[7] ) & 0xFF) );
}
double
getDouble( char const* buffer )
{
uint64_t retval = get64BitUInt( buffer );
return *reinterpret_cast<double*>( &retval );
}
(这对应于通常的网络字节顺序。如果是二进制格式
使用另一种惯例,你必须适应它。而且
reinterpret_cast
取决于实现定义的行为;你可以
必须重写为:
double
getDouble( char const* buffer )
{
union
{
double d;
uint64_t i;
} results;
results.i = get64BitUInt( buffer );
return results.d;
}
。或者甚至使用memcpy
从uint64_t
复制到double
。)
如果您的机器不使用IEEE浮点和外部格式
是IEEE,您必须将8字节字作为8字节无符号字
int(unsigned long long
),然后提取符号,指数和尾数
根据IEEE格式;如下所示:
double
getDouble( char const* buffer )
{
uint64_t tmp( get64BitUInt( buffer );
double f = 0.0 ;
if ( (tmp & 0x7FFFFFFFFFFFFFFF) != 0 ) {
f = ldexp( ((tmp & 0x000FFFFFFFFFFFFF) | 0x0010000000000000),
(int)((tmp & 0x7FF0000000000000) >> 52) - 1022 - 53 ) ;
}
if ( (tmp & 0x8000000000000000) != 0 ) {
f = -f ;
}
return f;
}
不要这样做,直到你确定你需要它为止。