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
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));
}
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
).
There are three options to avoid sequential reads:
- Have delimited records, store them sorted by key and use bisection
- Have fixed size records, store them sorted by key and use bisection
- 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.
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).