2

テキストファイルにデータを書き込むC関数があります。データは、float、int、および文字列で構成されています。次のようになります。

writeAsTextFile(  mystruct_t* myStructWithIntsFloatsAndStrings , const char* fileName);

これを行うために、fprintfへの呼び出しを使用します。

ここで、同じデータをバイナリとして書き込みたいと思います。2番目の関数writeAsBinaryFileを記述し、代わりにfwriteの呼び出しを使用できます。ただし、mystruct_tのデザインを変更するたびに、writeAsTextFileとwriteAsBinaryFileの両方を変更する必要があります。そしてもちろん、対応するreadAsTextFileとreadAsBinaryFile。これに加えて、これによりコードサイズが増加します。したがって、次のような1つのbin-or-text引数を持つ1つのジェネリック関数が必要です。

writeToFile( mystruct_t* myStructWithIntsFloatsAndStrings , const char* fileName, myEnumType_t eOption)

ここで、オプションは列挙型eBin=0およびeTxt=1などです。eOptionに応じて、関数はバイナリデータまたはテキストデータを書き込みます。

これを達成するための最良の方法が何であるかはわかりません。テキストとしての書き込みにもfwriteを使用する必要がありますか、マクロを使用する必要がありますか?(どこかで##ディレクティブの使用を見たことがありますが、使用したことはありません)、またはファイルに書き込む必要があるすべての場所でswitch / ifsステートメントを使用しますか?または、次のようなジェネリック関数を記述しますか myWriteFunction( void *data, char const type, myEnumType_t eOption)

それはwriteToFileによって呼び出されますか?

私はfread/fwriteとマクロの使用にあまり慣れていないので、ベストプラクティスのコメント、アイデアなどを歓迎します。

ありがとう

馬場

4

3 に答える 3

1

状況に応じて、ラッピング関数を作成するだけです。

writeToFile(...,bool isBinary) {
  if (isBinary) {
    // write as binary file
  } else {
    // write as text file
  }
}

MACROSに関する限り、すべての操作をバイナリまたはテキストにする場合にのみ役立ちます。

#ifdef __BINARY
#define WriteToFile(a,b,c,d,e) WriteToBinary(a,b,c,d,e)
#else
#define WriteToFile(a,b,c,d,e) WriteToText(a,b,c,d,e)
#endif

これは、winAPIでASCII関数とワイド文字関数を切り替えるために使用されます。

ところで:構造体にchar*またはstd:: stringが含まれている場合、文字列の内容はコピーされず、アドレスだけがコピーされます。これは、int*やstd::vectorなどの他のポインタにも当てはまります。

于 2010-10-02T01:31:57.977 に答える
1

さまざまなタイプのデータを書き込むための関数をいくつか作成できますstruct

writeInt(File *f, myEnumType_t eOption, int data);
writeFloat(File *f, myEnumType_t eOption, float data);
writeFloatArray(File *f, myEnumType_t eOption, float *data, size_t n_data);

..次に、バイナリまたはテキストのテストはそれらのそれぞれに隠されています。主な構造体書き込み関数は次のようになります(エラーチェックは省略されています)。

writeToFile(mystruct_t *myStruct, const char *fileName, myEnumType_t eOption)
{
    const char *fmode = eOption == EOPT_BIN ? "wb" : "w";
    FILE *f = fopen(filename, fmode);

    writeInt(f, eOption, myStruct->a);
    writeInt(f, eOption, myStruct->b);
    writeFloatArray(f, eOption, myStruct->values, myStruct->n_values);
    /* ... */
 }

したがって、構造のレイアウトを変更するだけで、1か所を変更する必要があります。

また、アプリケーションレベルの「タイプ」ごとに異なる書き込み関数を実装することもできます。たとえばwriteTemperature()、汎用とは異なる場合がありますwriteFloat()

于 2010-10-02T07:37:09.473 に答える
0

まず、機能を組み合わせないでください。実質的に節約にはなりません。

次に、構造体を使用するたびにテキスト関数として新しい書き込みを作成する必要があります。これを回避する方法はありません(一部の非標準のシリアル化ライブラリを除く)。

第3に、構造体メンバーの順序を変更せず、構造体の最後に新しいメンバーを追加するだけである限り、新しいバイナリライターまたはリーダーを作成する必要はありません。これを実現するには、構造体のサイズをファイルに書き込んでから、構造体をファイルに書き込む必要があります。

このようにして、read関数は構造体のサイズ(書き込まれたとき)を読み取り、読み取るバイト数を認識します。構造が変更された場合、プログラムは古い構造体バージョンからの一部を読み取ることができ、構造体の最後にある新しいメンバーは初期化されません。

編集

ポインターを使用して構造体を作成すると、ポインターの値が書き込まれます。ポインタは本質的にランダムなメモリの平和を指すため、構造を読み取るときは非常に注意する必要があります。b

構造体間の関係を維持したい場合は、独自のメカニズムを考え出す必要があります。これは難易度によって異なります。構造体を書き込むための事前定義された順序を考え出し、構造体を読み取るときにすべてのポインターを再構築する必要があります。

于 2010-10-02T01:32:36.033 に答える