Đọc dữ liệu từ tệp
12.1. Lớp ifstream
Để đọc dữ liệu từ tệp chúng ta sử dụng lớp ifstream. Lớp ifstream thừa kế các phương thức
của các lớp ios và istream. Nó cũng thừa kế phương thức:
close
của lớp fstreambase. Ngoài ra lớp ifstream có thêm các hàm tạo và các phương thức sau:
1. Hàm tạo:
ifstream() ; // Không đối
dùng để tạo một đối tượng ifstream (dòng nhập), chưa gắn với tệp.
2. Hàm tạo:
ifstream(const char *fn, int mode = ios::in,
int prot = filebuf::openprot);
dùng để tạo một đối tượng ifstream, mở tệp có tên fn để đọc và gắn đối tượng vừa tạo với tệp
được mở.
+ Tham số fn cho biết tên tệp.
+ Tham số mode có giá trị mặc định là ios::in (mở để đọc). Tham số này có thể là một hợp
của các giá trị sau:
ios::binary đọc theo kiểu nhị phân (mặc định theo kiểu văn bản)
ios::ate chuyển con trỏ tệp tới cuối tệp sau khi mở tệp
+ Tham số thứ ba prot quy định cấp bảo vệ của dòng tin, tham số này có thể bỏ qua vì nó đã
được gán một giá trị mặc định.
3. Hàm tạo:
ifstream(int fd);
dùng để tạo một đối tượng ifstream và gắn nó với một tệp có chỉ số fd đang mở.
(Để mở và lấy chỉ số (số hiệu) tệp có thể dùng hàm _open, xem cuốn Kỹ thuật Lập trình C
của tác giả)
4. Hàm tạo:
ifstream(int fd, char *buf, int n);
dùng để tạo một đối tượng ifstream , gắn nó với một tệp có chỉ số fd đang mở và sử dùng một
vùng nhớ n byte do buf trỏ tới làm bộ đệm.
5. Phương thức:
void open(const char *fn, int mode = ios::in,
int prot = filebuf::openprot);
dùng để mở tệp có tên fn để đọc và gắn nó với đối tượng ifstream. Các tham số của phương
thức có cùng ý nghĩa như trong hàm tạo thứ 2.
12.2. Các cách đọc tệp
Có 2 cách chính sau:
+ Cách 1: Dùng hàm tạo 2 để xây dựng một dòng nhập, mở một tệp để đọc và gắn tệp với
dòng nhập. Sau đó dùng toán tử nhập >> và các phương thức để nhập dữ liệu từ dòng nhập vừa
tạo như thể nhập dữ liệu từ cin (xem các mục trên)
+ Cách 2: Dùng hàm tạo 1 để xây dựng một dòng nhập. Sau đó dùng phương thức open để
mở một tệp cụ thể và cho gắn với dòng nhập vừa xây dựng. Khi không cần làm việc với tệp
này nữa, chúng ta có thể dùng phương thức close để chấm dứt mọi ràng buộc giữa dòng nhập
và tệp. Sau đó có thể gắn dòng nhập với tệp khác. Theo cách này, có thể dùng một dòng nhập
(đối tượng ifstream) để nhập dữ liệu từ nhiều tệp khác nhau.
12.3. Kiểm tra sự tồn tại của tệp, kiểm tra cuối tệp
+ Khi mở một tệp để đọc mà tệp không tồn tại thì sẽ phát sinh lỗi, khi đó phương thức bad
trả về giá trị khác không. Ví dụ để kiểm tra xem tệp DSTS (Danh sách thí sinh) đã tồn tại hay
không có thể dùng đoạn chương trình:
ifstream fin(“DSTS”);
if (fin.bad())
{
cout << “\nTep DSTS không tồn tai”;
exit(1);
}
+ Trong quá trình đọc, con trỏ tệp sẽ chuyển dần về cuối tệp. Khi con trỏ tệp đã ở cuối tệp
(hết dữ liệu) mà vẫn thực hiện một lệnh đọc thì phương thức eof sẽ cho giá trị khác không.
Chương trình dưới đây dùng phương thức eof để xác định độ dài (số byte) của tệp TC.EXE
(chú ý cần dùng kiểu đọc nhị phân):
//CT7_14.CPP
// Do dai tep
#include <iostream.h>
#include <fstream.h>
#include <conio.h>
#include <stdlib.h>
void main()
{
clrscr();
long dd=0; char ch;
ifstream f("TC.EXE",ios::in | ios::binary);
if (f.bad())
{
cout << "\nTep TC.EXE khong ton tai";
getch();
exit(1);
}
while(f.get(ch),!f.eof()) ++dd;
cout << "\n Do dai TC.EXE: " << dd;
getch();
}
412
12.4. Ví dụ
Chương trình dưới đây sẽ:
+ Đọc danh sách thí sinh từ tệp DS1.DL do chương trình trong muc
§
11 tạo ra.
+ In danh sách thí sinh vừa đọc.
+ Sắp xếp dẫy thí sinh (vừa nhập từ tệp) theo thứ tự giảm của tổng điểm.
+ Ghi danh sách thí sinh sau khi sắp xếp lên tệp DS3.DL
+ Đọc danh sách thí sinh từ tệp DS3.DL
+ In danh sách thí sinh đọc từ tệp DS3.DL
Chương trình sử dụng lớp TS (Thí sinh) có 4 phương thức:
void xuat();
void sapxep();
void ghitep(char *ttep);
void doctep(char *ttep);
//CT7_12.CPP
// Doc tep
#include <iostream.h>
#include <iomanip.h>
#include <fstream.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>
struct TSINH
{
char ht[25];
char ttinh[21];
int sobd;
float dt,dl,dh,td;
} ;
class TS
{
private:
int sots;
TSINH *ts;
public:
TS()
{
sots=0;
ts = NULL;
}
414
void xuat();
void sapxep();
void ghitep(char *ttep);
void doctep(char *ttep);
};
void TS::xuat()
{
cout << "\n\nSo thi sinh: " << sots;
cout << setprecision(1) << setiosflags(ios::showpoint);
for (int i=1; i<=sots; ++i)
{
cout << "\nThi sinh thu: " << i ;
cout << "\nHo ten: " << ts[i].ht ;
cout << "\nTinh - thanh pho: " << ts[i].ttinh ;
cout << "\nSo bao danh: " << ts[i].sobd ;
cout << "\nCac diem toan, ly, hoa: "
<< setw(5) << ts[i].dt
<< setw(5) << ts[i].dl
<< setw(5) << ts[i].dh ;
cout << "\nTong diem: " << ts[i].td ;
}
}
void TS::sapxep()
{
int n = sots;
for (int i=1; i< n; ++i)
for (int j=i+1; j<= n; ++j)
if (ts[i].td < ts[j].td)
{
TSINH tg = ts[i];
ts[i] = ts[j];
ts[j] = tg;
}
}
void TS::ghitep(char *ttep)
{
ofstream f;
f.open(ttep,ios::out|ios::noreplace);
if (f.bad())
416
{
cout << "\nTep " << ttep << " da ton tai";
cout << "\nCo ghi de? - C/K";
int ch=getch();
if (toupper(ch)=='C')
{
f.close();
f.open(ttep) ;
}
else
exit(1);
}
f << sots ;
f << setprecision(1) << setiosflags(ios::showpoint);
for (int i=1; i<=sots; ++i)
{
f << endl << setw(24) << ts[i].ht << setw(20) << ts[i].ttinh ;
f << endl << setw(6) << ts[i].sobd
<< setw(6) << ts[i].dt
<< setw(6) << ts[i].dl
<< setw(6) << ts[i].dh
<< setw(6) << ts[i].td ;
}
f.close();
}
void TS::doctep(char *ttep)
{
ifstream f;
f.open(ttep);
if (f.bad())
{
cout << "\nTep " << ttep << " khong ton tai";
getch();
exit(1);
}
f >> sots ;
f.ignore();
if (ts!=NULL) delete ts;
ts = new TSINH[sots+1];