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

如果您想在读取文件时进行随机访问,至少使用典型方法,您将需要使用固定大小的记录,因此假设您有 5 个字符作为名称,它将被存储为

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 回答
1

到目前为止,您所拥有的还不错,只是它无法处理字符串中有空格的情况(例如在地址中!)

您要做的是编写一个非常基本的数据库。您需要三个需要单独实现的操作(尽管在某些情况下将它们交织在一起可能会给您带来更好的性能,但我相信这不是您关心的问题)。

  • 插入:你已经实现了这个。您唯一可能想要更改的是" "to "\n"。这样,结构的每个字段都在一个新行中,并且您的空格问题得到解决。稍后阅读时,需要逐行阅读
  • 搜索:要搜索,您需要打开文件,逐个结构读取结构(其本身包括读取与您的结构字段对应的多行)并识别您感兴趣的实体。如何处理它们是另一个问题,但最简单的情况是返回数组(或向量)中匹配实体的列表。
  • 删除:这类似于搜索,但您必须重写文件。你所做的基本上是,再次逐个阅读结构,看看哪些符合你的删除标准。您忽略那些匹配的内容,并将其余部分(如插入部分)写入另一个文件。之后,您可以用新文件替换原始文件。

这是一个伪代码:

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

我建议将文件处理程序包装到一个类中,然后>> 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 回答
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

写入文件的代码是用户结构的成员函数吗?否则我看不出输出和结构之间有任何联系。

可能要做的事情:

  • 写 id 成员而不是 1
  • 对 id 使用计数器并在每次写入时将其递增
  • 不要写 id 并且在读取时使用行号作为 id
于 2012-05-04T14:44:11.890 回答