读取 C++ 行中的不同数据类型

read different data types in line c++

本文关键字:数据类型 C++ 读取      更新时间:2023-10-16

我从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); 
}

如何将其更改为有效的方法?

当您可以使用自定义格式轻松读取整个结构并自动填充正确的值时,有什么问题?

struct MyDataFormat {
  double d;
  int8 i1;
  float32 f[6];
  ..
};
MyDataFormat buffer;
fread(&buffer, sizeof(MyDataFormat), 1, file);

如果每一行的格式相同,我可能会一次将一行读入缓冲区,然后有一个函数将该缓冲区拉成单独的元素 - 更容易理解,更容易测试,适用于更大的文件,并且可能更有效率地执行更少的读取。

除了文件的"结构",我们还需要知道格式所涉及的数据类型,以及"行"的含义(如果格式)不是文本格式。 但是,一般来说,您将 1) 必须阅读适当大小的块,然后从中提取每个值,根据指定的格式。 对于整数值,这是公平的使用移位轻松提取无符号整数值;对于int8 , 在事实上,你只需要读取字节。 对于大多数机器来说,只是铸造将无符号整数转换为相应大小的有符号类型将工作,尽管这显然不能保证;如果unsigned char大于 CHAR_MAX ,您必须将其缩小才能获得
适当的值:类似于-(UCHAR_MAX+1 - value)应该执行技巧(对于char - 对于较大的类型,您还必须担心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;
}

. 甚至可以使用 memcpyuint64_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;
}

但是,在您确定需要它之前不要这样做。