1

私はC++にまったく慣れておらず、以下の構造の形式でテキストファイルにレコードを書き込む方法を模索しています。

struct user {
    int id;
    char username [20];
    char password [20];
    char name [20];
    char email [30];
    int telephone;
    char address [70];
    int level;
}; 

これまでのところ、うまく書き込むことができますが、レコード数を計算する方法がわからないため、ID番号を増やすことなく、データをファイルに書き込んだ後のファイルは次のようになります。

1 Nick pass Nick email tele address 1
1 user pass name email tele address 1
1 test test test test test test 1
1 user pass Nick email tele addy 1
1 nbao pass Nick email tele 207 1

次のコードを使用します。

ofstream outFile;

outFile.open("users.dat", ios::app);

// User input of data here

outFile << "\n" << 1 << " " << username << " " << password << " " << name << " "
        << email << " " << telephone << " " << address  << " " << 1;
cout << "\nUser added successfully\n\n";

outFile.close();

では、挿入時に各レコードの値をインクリメントするにはどうすればよいですか?また、ファイル内の特定のレコードをターゲットにするにはどうすればよいですか?

編集:私は各行を表示できる限り持っています:

  if (inFile.is_open())
    {
    while(!inFile.eof())
    {

    cout<<endl;
    getline(inFile,line);
    cout<<line<<endl;

    }
    inFile.close();
    }
4

6 に答える 6

1

ファイルハンドラーをクラスにラップしてから>> and <<、構造体の演算子をオーバーロードすることをお勧めします。これにより、インとアウトを制御できます。例えば

struct User{
...
};

typedef std::vector<User> UserConT;

struct MyDataFile
{
  ofstream outFile;
  UserConT User_container;

  MyDataFile(std::string const&); //
  MyDataFile& operator<< (User const& user); // Implement and/or process the record before to write
  MyDataFile& operator>> (UserConT & user); // Implement the extraction/parse and insert into container
  MyDataFile& operator<< (UserConT const & user); //Implement extraction/parse and insert into ofstream 
};

MyDataFile& MyDataFile::operator<< (User const& user)
{
  static unsigned myIdRecord=User_container.size();
  myIdRecord++;
  outFile << user.id+myIdRecord << ....;
  return *this;
}



int main()
{
   MydataFile file("data.dat");

   UserConT myUser;
   User a;
   //... you could manage a single record  
   a.name="pepe"; 
   ...
   file<<a;
   ..//

}
于 2012-05-04T15:08:33.810 に答える
1

これまでのところ、文字列にスペースがある場合(たとえば、アドレスに!)を処理できないことを除いて、悪くはありません。

あなたがやろうとしていることは、非常に基本的なデータベースを書くことです。別々に実装する必要がある3つの操作が必要です(ただし、それらを絡み合わせると、場合によってはパフォーマンスが向上する可能性がありますが、ここでは問題ではないと確信しています)。

  • 挿入:これはすでに実装されています。変更したいのはtoだけ" "です"\n"。このようにして、構造体のすべてのフィールドが改行され、スペースに関する問題が解決されます。後で読むときは、1行ずつ読む必要があります
  • 検索:検索するには、ファイルを開き、構造体ごとに構造体を読み取り(構造体フィールドに対応する多くの行を読み取ることで構成されます)、関心のあるエンティティを特定する必要があります。それらをどうするかは別の問題ですが、最も単純なケースは、配列(またはベクトル)内の一致するエンティティのリストを返すことです。
  • 削除:これは検索と似ていますが、ファイルを書き直す必要がある点が異なります。基本的には、構造体ごとにもう一度読んで、削除の基準に一致するものを確認します。一致するものを無視し、残りを(挿入部分のように)別のファイルに書き込みます。その後、元のファイルを新しいファイルに置き換えることができます。

擬似コードは次のとおりです。

Write-entity(user &u, ofstream &fout)
    fout << u.id << endl
         << u.username << endl
         << u.password << endl
         << ...

Read-entity(user &u, ifstream &fin)
     char ignore_new_line
     fin >> u.id >> ignore_new_line
     fin.getline(u.username, 20);
     fin.getline(u.password, 20);
     ...
     if end of file
         return fail

Insert(user &u)
     ofstream fout("db.dat");
     Write-entity(u, fout);
     fout.close();

Search(char *username) /* for example */
     ifstream fin("db.dat");
     user u;
     vector<user> results;
     while (Read-entity(u))
         if (strcmp(username, u.username) == 0)
             results.push_back(u);
     fin.close();
     return results;

Delete(int level) /* for example */
     ifstream fin("db.dat");
     ofstream fout("db_temp.dat");
     user u;
     while (Read-entity(u))
         if (level != u.level)
             Write-entity(u, fout);
     fin.close();
     fout.close();
     copy "db_temp.dat" to "db.dat"

補足:\nデータが書き込まれた後に配置することをお勧めします(テキストファイルが新しい行で終わるように)

于 2012-05-04T14:50:49.313 に答える
1

ファイルを読み取るときにランダムアクセスを行いたい場合は、少なくとも典型的な方法を使用して、固定サイズのレコードを使用する必要があります。

bob\0\0

または、パディングに使用する他のものは何でも、このようにして、レコード番号 * レコードサイズでインデックスを付けることができます。

現在の方法でインデックスをインクリメントするには、ファイルを読み取って既存の高いインデックスを見つけてインクリメントする必要があります。または、ファイルをメモリにロードし、新しいレコードを追加して、ファイルを書き戻すことができます

std::vector<user> users=read_dat("file.dat");
user user_=get_from_input();
users.push_back(user_);

then write the file back
std::ofstream file("file.dat");
for(size_t i=0; i!=users.size(); ++i) {
    file << users.at(i); 
   //you will need to implement the stream extractor to do this easily
}
于 2012-05-04T14:44:44.963 に答える
0

.Dat ファイルは通常、それ自体が単純なテキスト ファイルであり、メモ帳で開くことができます。したがって、単純にファイルの最終行を読み取り、それを読み取り、最初の文字を抽出して整数に変換できます。その後、値を増やして完了です。ここにいくつかのサンプルコード:

  #include <iostream.h>
  #include <fstream.h>
  using namespace std;

  int main(int argc, char *argv[])
  {
    ifstream in("test.txt");

  if(!in) {
       cout << "Cannot open input file.\n";
       return 1;
    }

     char str[255];

     while(in) {
       in.getline(str, 255);  // delim defaults to '\n'
        //if(in) cout << str << endl;
     }
    // Now str contains the last line , 
    if  ((str[0] >=48) || ( str[0] <=57))
    {
      int i = atoi(str[0]);
      i++;
    } 
    //i contains the latest value , do your operation now
    in.close();

     return 0;
     }
于 2012-05-04T14:43:36.353 に答える
0

ファイル形式が人間が読める形式である必要はないと仮定します。

構造体を次のようなファイルに書き出すことができます。

outFile.open("users.dat", ios::app | ios::binary);
user someValue = {};
outFile.write( (char*)&someValue, sizeof(user) );

int nIndex = 0;
user fetchValue = {};
ifstream inputFile.open("user.data", ios::binary);

inputFile.seekg (0, ios::end);

int itemCount = inputFile.tellg() / sizeof(user);

inputFile.seekg (0, ios::beg);

if( nIndex > -1 && nIndex < itemCount){
    inputFile.seekg ( sizeof(user) * nIndex , ios::beg);
    inputFile.read( (char*)&fetchValue, sizeof(user) );
}
于 2012-05-04T14:44:00.343 に答える
0

ファイルに書き込むコードは、ユーザー構造体のメンバー関数ですか? そうしないと、出力と構造体の間に関係がありません。

可能なこと:

  • 1 の代わりに id メンバーを書き込みます
  • IDにカウンターを使用し、書き込みごとにインクリメントします
  • ID を書き込まず、読み取り時に行番号を ID として使用する
于 2012-05-04T14:44:11.890 に答える