1

以下を含む構造を格納するデータベースのようなアプリケーションを開発しています。

struct Dictionary
{
    char *key;
    char *value;

    struct Dictionary *next;
};

ご覧のとおり、リンクされたリストを使用して情報を保存しています。しかし、問題はユーザーがプログラムを終了したときに始まります。情報をどこかに保存したい。そこで、fopen を使用してリンク リストを永続ファイルまたは一時ファイルに保存し、ユーザーがプログラムを起動したときにリンク リストを取得することを考えていました。リンクされたリストをコンソールに出力するメソッドは次のとおりです。

void PrintList()
{
    int count = 0;
    struct Dictionary *current;

    current = head;

    if (current == NULL)
    {
            printf("\nThe list is empty!");
        return;
    }

    printf("    Key \t  Value\n");
    printf("  ======== \t ========\n");

    while (current != NULL)
    {
        count++;
        printf("%d.  %s \t %s\n", count, current->key, current->value);
        current = current->next;
    }
}

したがって、このメソッドを変更して、printf の代わりに fprintf を介して情報を出力することを考えています。その後、プログラムはファイルから情報を取得するだけです。このファイルを読み書きする方法について誰か助けてもらえますか? 一時ファイルまたは通常ファイルの種類は何ですか? ファイルをどのようにフォーマットすればよいですか(最初にキー、次に値、次に改行文字を考えていたように)?

4

4 に答える 4

2

ファイルはおそらく通常のはずです。次回アプリケーションを起動したときに一時ファイルがそこにあるとは限りません。また、そこにあるあなたのフォーマットは、人間にとってはきれいに見えますが、機械にとってはそれほどきれいではありません. 独自のバイナリ ファイル形式を作成するか、XML (または JSON ?) を使用することをお勧めします。おそらく、次のようにかなり簡単にフォーマットできます

key1\0value1\0key2\0value2\0....

疑似コードの簡単な例を書きます。

//To write...
Dictionary *this=begin_list;
while(this!=null){
  for(i=0;i<strlen(this->key);i++){
    write_byte(this->key[i]);
  }
  for(i=0;i<strlen(this->value);i++){
    write_byte(this->value[i]);
  }
  this=this->next;
}

//to read...
Dictionary *prev;
Dictionary *this;
char *buffer;
while(!eof){
  buffer=malloc(MAX_STRING_LEN);
  int i=0;
  this=malloc(sizeof(Dictionary)
  while(i<MAX_STRING_LEN){ //note no error checking
    buffer[i]=read_byte();
    if(buffer[i]==0){
      break;
    }
  }
  this->key=buffer;
  buffer=malloc(MAX_STRING_LEN)
  while(i<MAX_STRING_LEN){ //note no error checking
    buffer[i]=read_byte();
    if(buffer[i]==0){
      break; 
    }
  }
  this->value=buffer;
  if(prev!=null){
    prev->next=this;
  }
  this->next=null;
  prev=this;
}

私はそれが悪い例であることを知っています。scanf などを使用すると、作業が大幅に簡単になると思いますが、私の C スキルはさびてきています。

于 2010-04-14T20:32:32.847 に答える
2

基本的な問題は、ポインターが外部ストレージに変換されないことです。プログラムが再度実行されたときに、同じメモリ範囲 (アドレス) を持つという保証はありません。この原則を踏まえると、データを保存する別の方法があります。

永続データのプロセス:
1. 小規模または大規模なデータベースを使用します。
2. データをスキャン可能な形式の ASCII テキストに変換します。
3. 固定長のバイナリ レコード
を使用します。 4. 可変サイズのバイナリ レコードを使用します
。 5. ポインタの代わりにファイル オフセットを使用して辞書データ構造を実装します。

データベース
の使用 プロ仕様のアプリケーション (テスト済みで動作するもの) でデータを管理します。これにより、データの保存と取得ではなく、データの使用に集中できます。

スキャン可能な形式に変換する
ここでの考え方は、データを簡単に取得して維持できる形式でファイルに書き込むことです。例には、カンマ区切り値 (CSV)、XML、および INI が含まれます。これには、データを読み書きするためのコードが必要です。支援するライブラリがあります。

固定長のバイナリ レコードを使用する 固定
長のレコードでは、データがファイルから読み取られ、辞書に挿入されます。バイナリ ファイルは、データの転送に関しては非常に効率的ですが、特にオペレーティング システムのバージョンが変更された場合、プラットフォームが変更された場合、またはコンパイラのバージョンが変更された場合は、移植性が低くなります。テキスト レコードのスペースが無駄になる場合があります。

可変サイズのバイナリ レコードを使用する
この手法はスペースを節約しますが、処理時間が長くなります。次のレコードの場所を見つけるために、各レコードを処理する必要があります。レコードへのランダム アクセスは困難です。それ以外は、固定長のバイナリ レコードに似ています。

ファイルにディクショナリ データ構造を実装する
ポインターの代わりにファイル オフセットを使用する点を除いて、メモリ ベースのデータ構造と同じアルゴリズムです。ファイルの末尾に新しいレコードを追加できます。削除されたエントリの再利用は困難であり、断片化につながります。断片化は、新しいファイルを書き込むことで解決できます。これだけの労力を費やしているのであれば、既存のデータベース アプリケーションを使用することもできます。

于 2010-04-14T20:56:59.147 に答える
1

ファイルを読み書きできる 1 つの方法は、次のように freopen を使用することです。コードがたくさん。

情報をプレーン テキストで保存することもできますが、これを行う最善の方法は、情報をバイナリ ファイルに保存することだと思います。fread と fwrite に関するこの検索情報について詳しくは、こちらをご覧ください。

于 2010-04-14T20:43:46.833 に答える
0

この問題を解決する 1 つの方法を次に示します。

次のようなリスト項目のデータ構造を作成します。

struct DictionaryArchive {
    char key[MAX_KEY_LENGTH];
    char value[MAX_VALUE_LENGTH];
    int next;
};

期待するデータに従って とMAX_KEY_LENGTHの値を決定する必要があります。MAX_VALUE_LENGTH

次に、連結リストをこれらの構造の配列に変換します。次の項目を見つけるためのポインターを格納する代わりに、次の項目の配列インデックスを格納します。これにより、リストが、各要素が予測可能なサイズである形式に変換され、リスト全体が 1 つの連続するメモリ スパンになります。これで、fwriteこの配列をバイナリ ファイルに保存してアーカイブし、fread元に戻して復元することができます。

上記の固定サイズの配列を使用するよりもはるかにスペース効率の良い代替手段charは、静的構造を使用する代わりにカスタム ファイル形式を定義することです。あなたの場合、次のようなファイル形式を使用して、データを取得可能な方法で保存できます。

  • リストはファイルに順番に書き込まれます。先頭から始まりnext、末尾へのポインターに従います。
  • 各リスト項目は、次の順序で 4 つのデータ フィールドを使用して格納されます。
    1. 16 ビット整数、key_length
    2. key_length要素を持つ 8 ビットの char 配列、key_data
    3. 16 ビット整数、value_length
    4. value_length要素を持つ 8 ビットの char 配列、value_data

これで、リストをたどって、データをノードごとにファイルにダンプできます。データを再構築するには、バイナリ ファイルを読み込んで、struct Dictionaryエントリごとに新しい要素を生成し、ファイルに表示される順序でそれらをリンクします。

データをデータ ファイルに書き込むコードは、次のようになります (未テスト、例示目的のみ)。

FILE* fd;
size_t len;
struct Dictionary* pDict = list_head;
fd = fopen("output_file.dat", "w");

// Walk through the list, storing each node
while (pDict != NULL) {
    // Store key
    len = strlen(pDict->key);
    fwrite(&len, sizeof(len), 1, fd);
    fwrite(pDict->key, len, sizeof(char), fd);

    // Store value
    len = strlen(pDict->value);
    fwrite(&len, sizeof(len), 1, fd);
    fwrite(pDict->value, len, sizeof(char), fd);

    // Move to next list node
    pDict = pDict->next;
};

fclose(fd);

データを読み取るコードは非常に似ています (書き込みではなく読み取り、struct Dictionaryループの反復ごとに新しいオブジェクトを作成します)。

于 2010-04-14T21:24:43.577 に答える