简体   繁体   English

写入和读取.dat文件C ++的记录

[英]Write and read records to .dat file C++

I am quite new to C++ and am trying to work out how to write a record in the format of this structure below to a text file: 我是C ++的新手,我正在尝试研究如何将以下结构格式的记录写入文本文件:

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

So far, I'm able to write to it fine but without an incremented id number as I don't know how to work out the number of records so the file looks something like this after I've written the data to the file. 到目前为止,我能够写得很好,但没有增加的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

Using the following code: 使用以下代码:

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();

So, how can I increment the value for each record on insertion and how then target a specific record in the file? 那么,如何在插入时增加每条记录的值,然后如何定位文件中的特定记录?

EDIT: I've got as far as being able to display each line: 编辑:我已经能够显示每一行:

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

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

    }
    inFile.close();
    }

Using typical methods at least you will need to use fix size records if you want to have random access when reading the file so say you have 5 characters for name it will be stored as 使用典型方法至少你需要使用修复大小记录,如果你想在阅读文件时有随机访问,所以说你有5个字符的名称它将被存储为

bob\0\0

or whatever else you use to pad, this way you can index with record number * record size. 或者你用来填充的任何其他内容,这样你就可以使用记录号*记录大小进行索引。

To increment the index you in the way you are doing you will need to the read the file to find the high existing index and increment it. 要按照您的方式递增索引,您需要读取文件以查找高现有索引并递增它。 Or you can load the file into memory and append the new record and write the file back 或者,您可以将文件加载到内存中并附加新记录并将文件写回

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
}

What you have so far is not bad, except that it cannot handle cases where there is space in your strings (for example in address!) 到目前为止你所拥有的并不坏,除了它无法处理字符串中有空格的情况(例如在地址中!)

What you are trying to do is write a very basic data base. 你要做的是写一个非常基础的数据库。 You require three operations that need to be implemented separately (although intertwining them may give you better performance in certain cases, but I'm sure that's not your concern here). 您需要三个需要单独实施的操作(尽管在某些情况下交织它们可能会给您带来更好的性能,但我确信这不是您的关注点)。

  • Insert: You already have this implemented. 插入:您已经实现了这一点。 Only thing you might want to change is the " " to "\\n" . 你可能想要改变的只是" ""\\n" This way, every field of the struct is in a new line and your problem with spaces are resolved. 这样,struct的每个字段都在一个新行中,并解决了空格问题。 Later when reading, you need to read line by line 稍后阅读时,您需要逐行阅读
  • Search: To search, you need to open the file, read struct by struct (which itself consists of reading many lines corresponding to your struct fields) and identifying the entities of your interest. 搜索:要搜索,您需要打开文件,按结构读取struct(它本身包括读取与您的struct字段对应的许多行)并标识您感兴趣的实体。 What to do with them is another issue, but simplest case would be to return the list of matching entities in an array (or vector). 如何处理它们是另一个问题,但最简单的情况是返回数组(或向量)中匹配实体的列表。
  • Delete: This is similar to search, except you have to rewrite the file. 删除:这与搜索类似,但您必须重写文件。 What you do is basically, again read struct by struct, see which ones match your criteria of deletion. 你所做的基本上是,再次按结构读取结构,看看哪些符合你的删除标准。 You ignore those that match, and write (like the insert part) the rest to another file. 您忽略那些匹配,并将其余部分写入(如插入部分)另一个文件。 Afterwards, you can replace the original file with the new file. 之后,您可以使用新文件替换原始文件。

Here is a pseudo-code: 这是一个伪代码:

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"

Side note: It's a good idea to place the \\n after data has been written (so that your text file would end in a new line ) 附注:在写完数据之后放置\\n是个好主意(这样你的文本文件将以新行结束

I suggest to wrap the file handler into a Class, and then overload the operator >> and << for your struct, with this was you will control the in and out. 我建议将文件处理程序包装到一个Class中,然后为你的struct重载operator >> and << ,这样你就可以控制进出了。 For instance 例如

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;
   ..//

}

A .Dat file is normally a simple text file itself that can be opened with notepad . .Dat文件通常是一个简单的文本文件,可以使用记事本打开。 So , you can simply read the Last Line of the file , read it , extract the first character , convert it into integer . 因此,您只需读取文件的最后一行,读取它,提取第一个字符,将其转换为整数。 THen increment the value and be done . 然后递增值并完成。 Some sample code here : 这里有一些示例代码:

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

Assuming your file format doesn't not need to be human readable. 假设您的文件格式不需要是人类可读的。

You can write the struct out to file such as. 您可以将结构写入文件,例如。

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

The code that writes to the file is a member function of the user struct? 写入文件的代码是用户结构的成员函数? Otherwise I see no connection with between the output and the struct. 否则,我看到输出和结构之间没有任何关联。

Possible things to do: 可能的事情:

  • write the id member instead of 1 写id成员而不是1
  • use a counter for id and increment it at each write 使用id的计数器并在每次写入时递增它
  • don't write the id and when reading use the line number as id 不要写id,在阅读时使用行号作为id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM