sequentially reading a structs from binary file in

2019-07-25 16:10发布

问题:

I'm trying to write a program, when the program is performing an operation (Example: search, update, or add), it should be direct access. The program should not read all the records sequentially to reach a record.

 #include <iostream>
#include <fstream>
#include <string>

using namespace std;

struct Student{
    int Id;
    int Money;
    int Age;
    char name[15];
};

void main(){
    Student buffer;
    ofstream BinaryFile("student", ios::binary);
    ifstream WorkerText("worker.txt");

//-------------------------------------------------------------------------------------------------------------
    while( WorkerText.good() ){                     
        WorkerText>> buffer.Age >> buffer.name >> buffer.name >> buffer.name;
        BinaryFile.write(  (char *) &buffer, sizeof(Student)  );    

    }
    BinaryFile.close();
//-------------------------------------------------------------------------------------------------------------
    ifstream ReadBinary( "student", ios::binary | ios::out );
    while( BinaryFile.good() ){                     
        ReadBinary.read((char*)&buffer,sizeof(Student));
        cout<<buffer.Age;

    }


//-------------------------------------------------------------------------------------------------------------


system("pause");
}

I stucked here I could not read sequentially how can I solve this

回答1:

You can skip sequential read only if the file contains structures of the same size, or uses some index table.

For the case of structures of same size:

void ReadStudent(istream &src, Student &dst)
{
    src.read(&dst, sizeof(dst));
}

void GoToStudentIndex(istream &src, size_t idx)
{
   src.seekg(idx * sizeof(Student), is.beg);
 }

The functions above assume you are writing data as follows:

void WriteStudent(ostream &dst, const Student &src)
{
    dst.write(&src, sizeof(src));
}


回答2:

You are using "out" mode when you open the student file for input:

ifstream ReadBinary( "student", ios::binary | ios::out );  
^^^^^^^^                                      ^^^^^^^

Try this:

ifstream ReadBinary("student", ios::binary);  

The ifstream constructor already opens the file in input mode (ios::in).



回答3:

There are three options to avoid sequential reads:

  1. Have delimited records, store them sorted by key and use bisection
  2. Have fixed size records, store them sorted by key and use bisection
  3. Have separate index file (key => offset in the data file) of much smaller size than the data file, preload it first and use for direct read by the offset.


回答4:

When we want to do search (and subsequent update) but store records in flat file sequentially, you need to have external index to help you get direct access to desired record ! Say in this case you want to search student by name and then update record, you can do some thing like this:

// Store in map name and the position of record
std::map name2offset;

void writeRecord(const Student& student)
{
    name2offset[string(student.name)]=BinaryFile.tellp();
    BinaryFile.write(reinterpret_cast<char*>(&student), sizeof(Student));
}

// Return true if updated successfully else false.
bool update(const string& name, Student &newRecord)
{
    std::map<char,long>::iterator itr = name2offset.find(name);
    if (itr != name2offset.end()) {
        BinaryFile.seekp(itr->second);
        BinaryFile.write(reinterpret_cast<char*>(&newRecord), sizeof(Student));

        return true;
    }

    return false;
}

These all assume that your struct is fixed size one (which it is in your example).