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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10450900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:04:27  来源:igfitidea点击:

Write and read records to .dat file C++

c++file-iorecord

提问by nbaosullivan

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

采纳答案by Shahbaz

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". This way, every field of the struct is in a new line and your problem with spaces are resolved. 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. 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.
  • 插入:您已经实现了这一点。您可能唯一想要更改的是" "to "\n"。这样,结构的每个字段都在一个新行中,您的空格问题得到解决。以后阅读时,需要逐行阅读
  • 搜索:要搜索,您需要打开文件,逐个读取结构(它本身包括读取与您的结构字段相对应的许多行)并确定您感兴趣的实体。如何处理它们是另一个问题,但最简单的情况是返回数组(或向量)中匹配实体的列表。
  • 删除:这类似于搜索,但您必须重写文件。您所做的基本上是,再次逐个读取结构,看看哪些符合您的删除标准。您忽略匹配的那些,并将其余部分(如插入部分)写入另一个文件。之后,您可以用新文件替换原始文件。

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 \nafter data has been written (so that your text file would end in a new line)

旁注:将\n数据写入后放置是个好主意(这样您的文本文件将以新行结尾

回答by 111111

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

}

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

要以您正在执行的方式增加索引,您需要读取文件以找到现有的高索引并增加它。或者您可以将文件加载到内存中并附加新记录并将文件写回

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

回答by Agus

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. For instance

我建议将文件处理程序包装到一个类中,然后>> and <<为您的结构重载运算符,这样您就可以控制进出。例如

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

回答by CyprUS

A .Dat file is normally a simple text file itself that can be opened with notepad . 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 :

.Dat 文件通常是一个简单的文本文件本身,可以用记事本打开。因此,您可以简单地读取文件的最后一行,读取它,提取第一个字符,将其转换为整数。然后增加值并完成。这里的一些示例代码:

##代码##

回答by Nico

Assuming your file format doesn't not need to be human readable.

假设您的文件格式不需要是人类可读的。

You can write the struct out to file such as.

您可以将结构写入文件,例如。

##代码##

回答by Marius

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
  • use a counter for id and increment it at each write
  • don't write the id and when reading use the line number as id
  • 写 id 成员而不是 1
  • 使用计数器作为 id 并在每次写入时增加它
  • 不要写id,读取时使用行号作为id