1

私は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); 
}

これを効率的な方法に変更するにはどうすればよいですか?

4

3 に答える 3

2

カスタム形式で構造体全体を簡単に読み取り、フィールドに正しい値を自動的に入力できる場合、何が問題になるでしょうか?

struct MyDataFormat {
  double d;
  int8 i1;
  float32 f[6];
  ..
};

MyDataFormat buffer;

fread(&buffer, sizeof(MyDataFormat), 1, file);
于 2012-04-16T16:55:54.600 に答える
1

ファイルの「構造」に加えて、関連するデータ型の形式と、形式がテキスト形式でない場合の「行」の意味を知る必要があります。ただし、一般的には、1) 適切なサイズのブロックを読み取り、指定された形式に従って、そこから各値を抽出する必要があります。整数値の場合、シフトを使用して符号なし整数値を抽出するのはかなり簡単です。実際にint8は、バイトを読み取るだけです。ほとんどのマシンでは、符号なし整数を対応するサイズの符号付き型にキャストするだけで機能しますが、これは明示的に保証されていません。unsigned char が より大きい場合は、 適切な値CHAR_MAXを取得するために縮小する必要があります。
-(UCHAR_MAX+1 - value)charUINT_MAX+1s—より大きな型の場合、オーバーフローするという事実についても心配する必要があります)。

外部フォーマットが IEEE であり、マシンが使用するものでもある場合(Windows および Unix マシンの場合は通常のケースですが、メインフレームの場合はめったにありません)、符号なしの 4 または 8 バイト整数を読み取ることができます (ここでもシフトを使用します)。次のように pun と入力します。

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;
}

. または、 a から a にコピーするために使用することもできますmemcpy。)uint64_tdouble

お使いのマシンが IEEE 浮動小数点を使用しておらず、外部フォーマットが IEEE の場合、8 バイトの単語を 8 バイトの unsigned 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;
}

ただし、必要になることが確実になるまでは、これを行わないでください。

于 2012-04-16T17:51:11.440 に答える
1

各行が同じ形式の場合、一度に 1 行ずつバッファーに読み込み、そのバッファーを個別の要素に分割する関数を用意します。理解しやすく、テストしやすく、より大きなファイルで動作し、おそらくより効率的です。より少ない読み取りを行います。

于 2012-04-16T16:55:07.760 に答える