Programming Language & Its Applications β Virtual Functions and File Handling, NEC licence examination syllabus (Nepal Engineering Council).
The same << and >> you use on cout, plus getline, read/write, and random access with seekg.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <limits>
int main() {
/* build a test file */
{ std::ofstream f("data.txt");
f << "101 Ram Bahadur 87.5\n"
<< "102 Sita Devi 91.0\n"; }
/* 1. FORMATTED β note >> stops at each space, so a
two-word name needs TWO reads */
{
std::ifstream in("data.txt");
int roll; std::string first, last; double m;
while (in >> roll >> first >> last >> m)
std::cout << " formatted: " << roll << " ["
<< first << " " << last << "] " << m << "\n";
}
/* 2. LINE β reads spaces, so the whole record arrives */
{
std::ifstream in("data.txt");
std::string line;
while (std::getline(in, line))
std::cout << " getline : [" << line << "]\n";
}
/* the >> then getline trap, demonstrated and fixed */
{
std::istringstream s("42\nsome text here\n");
int n; std::string rest;
s >> n;
std::getline(s, rest);
std::cout << " BROKEN: n=" << n
<< " rest=[" << rest << "]\n";
}
{
std::istringstream s("42\nsome text here\n");
int n; std::string rest;
s >> n;
s.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::getline(s, rest);
std::cout << " FIXED : n=" << n
<< " rest=[" << rest << "]\n";
}
/* 3. CHARACTER β count what is there */
{
std::ifstream in("data.txt");
long chars = 0, lines = 0, digits = 0;
char c;
while (in.get(c)) {
chars++;
if (c == '\n') lines++;
if (c >= '0' && c <= '9') digits++;
}
std::cout << " chars=" << chars << " lines=" << lines
<< " digits=" << digits << "\n";
}
return 0;
}
Output:
formatted: 101 [Ram Bahadur] 87.5
formatted: 102 [Sita Devi] 91
getline : [101 Ram Bahadur 87.5]
getline : [102 Sita Devi 91.0]
BROKEN: n=42 rest=[]
FIXED : n=42 rest=[some text here]
chars=40 lines=2 digits=12
#include <iostream>
#include <fstream>
#include <cstring>
/* A binary-writable record must be "plain old data":
fixed-size members, NO std::string, NO pointers, NO
virtual functions. A std::string member holds a POINTER
to heap data β writing its bytes saves the pointer, not
the text, and reading it back gives a dangling pointer. */
struct Student {
int roll;
char name[24]; /* fixed array, NOT std::string */
float marks;
};
int main() {
Student out[3] = {
{101, "", 87.5f}, {102, "", 91.0f}, {103, "", 76.5f}
};
std::strcpy(out[0].name, "Ram Bahadur");
std::strcpy(out[1].name, "Sita Devi");
std::strcpy(out[2].name, "Hari Prasad");
std::cout << " sizeof(Student) = " << sizeof(Student) << "\n";
/* WRITE all three in one call */
{
std::ofstream f("students.dat", std::ios::binary);
f.write(reinterpret_cast<const char*>(out),
3 * sizeof(Student));
}
/* READ them back */
{
std::ifstream f("students.dat", std::ios::binary);
Student in[3];
f.read(reinterpret_cast<char*>(in), 3 * sizeof(Student));
std::cout << " gcount = " << f.gcount() << " bytes\n";
for (const auto &s : in)
std::cout << " " << s.roll << " " << s.name
<< " " << s.marks << "\n";
}
/* file size -> record count */
{
std::ifstream f("students.dat", std::ios::binary);
f.seekg(0, std::ios::end);
long bytes = static_cast<long>(f.tellg());
std::cout << " file " << bytes << " bytes = "
<< bytes / (long)sizeof(Student) << " records\n";
}
return 0;
}
Output:
sizeof(Student) = 32
gcount = 96 bytes
101 Ram Bahadur 87.5
102 Sita Devi 91
103 Hari Prasad 76.5
file 96 bytes = 3 records
#include <iostream>
#include <fstream>
#include <cstring>
struct Student { int roll; char name[24]; float marks; };
int main() {
/* create 5 records */
{
std::ofstream f("db.dat", std::ios::binary);
const char *names[] = {"Ram","Sita","Hari","Gita","Bikash"};
for (int i = 0; i < 5; i++) {
Student s{101+i, "", 60.0f + i*7};
std::strncpy(s.name, names[i], sizeof s.name - 1);
f.write(reinterpret_cast<const char*>(&s), sizeof s);
}
}
std::fstream f("db.dat", std::ios::in | std::ios::out
| std::ios::binary);
const long SZ = sizeof(Student);
/* jump straight to record 3 */
Student s;
f.seekg(3 * SZ, std::ios::beg);
f.read(reinterpret_cast<char*>(&s), SZ);
std::cout << " rec 3: " << s.roll << " " << s.name
<< " " << s.marks
<< " (tellg now " << f.tellg() << ")\n";
/* modify it in place */
s.marks += 10.0f;
f.seekp(3 * SZ, std::ios::beg);
f.write(reinterpret_cast<const char*>(&s), SZ);
f.flush();
f.seekg(3 * SZ, std::ios::beg);
f.read(reinterpret_cast<char*>(&s), SZ);
std::cout << " rec 3 after +10: " << s.marks << "\n";
/* the LAST record, via SEEK_END */
f.seekg(-SZ, std::ios::end);
f.read(reinterpret_cast<char*>(&s), SZ);
std::cout << " last : " << s.roll << " " << s.name << "\n";
/* backwards traversal β impossible without seeking */
f.clear();
f.seekg(0, std::ios::end);
long count = static_cast<long>(f.tellg()) / SZ;
std::cout << " reverse: ";
for (long i = count - 1; i >= 0; i--) {
f.seekg(i * SZ, std::ios::beg);
f.read(reinterpret_cast<char*>(&s), SZ);
std::cout << s.roll << " ";
}
std::cout << "\n";
return 0;
}
Output:
rec 3: 104 Gita 81 (tellg now 128)
rec 3 after +10: 91
last : 105 Bikash
reverse: 105 104 103 102 101
CREATE INDEX. If you want to see it done properly, SQLite is a single readable C file that implements exactly this: fixed-size pages, a B-tree index, and seek-based access. Search "SQLite file format documentation" β it is unusually well written, and recognising your own seekg(n * sizeof(Record)) inside a real database engine is a genuinely satisfying moment.>>-then-getline leftover-newline trap and its ignore() fix is asked directly. For binary I/O, know that read/write take char* (hence the cast), that gcount() reports bytes read, and that a std::string member cannot be written binary. The record offset formula n Γ sizeof(Record) with seekg/tellg is a guaranteed numerical β practise beg, cur and negative end offsets.Create a free account to tick topics off, take notes as you read, watch the video lessons and get a day-by-day study plan built around your exam date.
Loadingβ¦