Ghi dữ liệu lên file văn bản
#include #include
using namespace std;
int main()
{
ofstream myfile (“example.txt”);
if (myfile.is_open()
{
myfile<<”Dong 1 da ghi\n”;
myfile<<”Dong 2 da ghi\n”;
myfile.close();
}
else cout<<”Khong the ghi du lieu len file”;
return 0;
}
Ví dụ trên cho thấy việc ghi dữ liệu lên file văn bản nhờ vào toán tử <<. Ví dụ tiếp theo sau đây sẽ minh họa cho việc đọc dữ liệu từ file văn bản bằng toán tử >>.
Đọc dữ liệu từ file văn bản
#include #include
#include
using namespace std;
int main(){
ifstream myfile (“example.txt”);
if (myfile.is_open(){
while(!myfile.eof()){
getline(myfile, line);
cout<
<
}
myfile.close();
}
else cout<<”Khong the ghi du lieu len file”;
return 0;
}
Trong ví dụ này, chúng ta có sử dụng hàm thành viên eof của đối tượng ifstream. Hàm thành viên này có chức năng kiểm tra vị trí đọc đã là vị trí cuối cùng của file hay chưa, nếu chưa, dữ liệu từ file sẽ tiếp tục được đọc. Ngược lại, nó sẽ dừng việc đọc dữ liệu.
Kiểm tra trạng thái của các cờ hiệu
Ví dụ trên cho ta một các thức để kiểm tra trạng thái của các cờ hiệu. Bảng sau đây sẽ liệt kê các trạng thái cờ hiệu có thể được sử dụng trong C++.
Trạng thái
Giải thích
bad()
Nếu tác vụ đọc/ghi file bị lỗi, nó sẽ trả về giá trị true; ngược lại, nó sẽ trả về giá trị false.
fail()
Trả về giá trị true trong trường hợp như bad(), nhưng nếu gặp lỗi về định dạng, nó cũng trả về giá trị true (ví dụ đọc số từ một file văn bản).
eof()
Trả về giá trị true nếu file đã được đọc đến vị trí cuối cùng của file, ngược lại, trả về giá trị false.
good()
Nó sẽ trả về giá trị true nếu bad(), fail() và eof() không phát sinh lỗi.
Để thiết lập lại các mức kiểm tra trạng thái cờ hiệu, ta sử dụng phương thức thành viên clear().
Các hàm thành viên của các lớp làm việc với File
Con trỏ get và put
Mọi đối tượng luồng xuất nhập đều có ít nhất một con trỏ luồng:
- Luồng ifstream có con trỏ istream mà ta gọi là con trỏ get để trỏ vào phần tử có thể đọc dữ liệu.
- Luồng ofstream có con trỏ ostream mà ta gọi là con trỏ put để trỏ vào phần tử có thể ghi dữ liệu.
- Luồng fstream có cả hai con trỏ get và put để đọc và ghi dữ liệu.
Những con trỏ luồng nội tại này trỏ vào vị trí đọc và ghi với luồng có thể sử dụng các hàm thành viên sau đây:
Hàm thành viên tellg() và tellp()
Hai hàm thành viên này không có tham số và trả về giá trị của một kiểu dữ liệu dạng pos_type. Kiểu dữ liệu này bản chất là một số nguyên integer. Nó mô tả vị trí hiện tại của của con trỏ luồng get và con trỏ luồng put.
Hàm thành viên seekg() và seekp()
Những hàm thành viên này cho phép chúng ta thay đổi vị trí hiện tại của con trỏ luồng get và put. Cả hai hàm này được chồng chất với hai prototype khác nhau. Prototype thứ nhất:
seekg(vị_trí);
seekp(vị_trí);
Việc sử dụng các prototype này giúp làm thay đổi vị trí tuyệt đối (vị trí này tính từ đầu file). Kiểu dữ liệu của tham số này trùng với kiểu dữ liệu của hai hàm tellg() và tellp() ở trên.
Prototype thứ hai:
seekg(vị_trí, kiểu);
seekp(vị_trí, kiểu);
Việc sử dụng prototype này sẽ làm thay đổi vị trí hiện tại của con trỏ get và con trỏ put được xác định theo vị trí tương đối theo tham số vị_trí và tham số kiểu. vị_trí của một thành viên thuộc kiểu dữ liệu off_type, nó cũng là một kiểu số nguyên, nó tương ứng với vị trí của con trỏ get/set được đặt vào. Tham số kiểu là một kiểu dữ liệu seekdir, nó là một kiểu enum để xác định vị_trí của con trỏ get/put kể từ kiểu, nó có thể nhận một trong các giá trị sau đây.
ios::beg using namespace std;
int main(){
ifstream myfile (“example.txt”);
if (myfile.is_open(){
while(!myfile.eof()){
getline(myfile, line);
cout<
<
}
myfile.close();
}
else cout<<”Khong the ghi du lieu len file”;
return 0;
}
Trong ví dụ này, chúng ta có sử dụng hàm thành viên eof của đối tượng ifstream. Hàm thành viên này có chức năng kiểm tra vị trí đọc đã là vị trí cuối cùng của file hay chưa, nếu chưa, dữ liệu từ file sẽ tiếp tục được đọc. Ngược lại, nó sẽ dừng việc đọc dữ liệu.
Kiểm tra trạng thái của các cờ hiệu
Ví dụ trên cho ta một các thức để kiểm tra trạng thái của các cờ hiệu. Bảng sau đây sẽ liệt kê các trạng thái cờ hiệu có thể được sử dụng trong C++.
Trạng thái
Giải thích
bad()
Nếu tác vụ đọc/ghi file bị lỗi, nó sẽ trả về giá trị true; ngược lại, nó sẽ trả về giá trị false.
fail()
Trả về giá trị true trong trường hợp như bad(), nhưng nếu gặp lỗi về định dạng, nó cũng trả về giá trị true (ví dụ đọc số từ một file văn bản).
eof()
Trả về giá trị true nếu file đã được đọc đến vị trí cuối cùng của file, ngược lại, trả về giá trị false.
good()
Nó sẽ trả về giá trị true nếu bad(), fail() và eof() không phát sinh lỗi.
Để thiết lập lại các mức kiểm tra trạng thái cờ hiệu, ta sử dụng phương thức thành viên clear().
Các hàm thành viên của các lớp làm việc với File
Con trỏ get và put
Mọi đối tượng luồng xuất nhập đều có ít nhất một con trỏ luồng:
- Luồng ifstream có con trỏ istream mà ta gọi là con trỏ get để trỏ vào phần tử có thể đọc dữ liệu.
- Luồng ofstream có con trỏ ostream mà ta gọi là con trỏ put để trỏ vào phần tử có thể ghi dữ liệu.
- Luồng fstream có cả hai con trỏ get và put để đọc và ghi dữ liệu.
Những con trỏ luồng nội tại này trỏ vào vị trí đọc và ghi với luồng có thể sử dụng các hàm thành viên sau đây:
Hàm thành viên tellg() và tellp()
Hai hàm thành viên này không có tham số và trả về giá trị của một kiểu dữ liệu dạng pos_type. Kiểu dữ liệu này bản chất là một số nguyên integer. Nó mô tả vị trí hiện tại của của con trỏ luồng get và con trỏ luồng put.
Hàm thành viên seekg() và seekp()
Những hàm thành viên này cho phép chúng ta thay đổi vị trí hiện tại của con trỏ luồng get và put. Cả hai hàm này được chồng chất với hai prototype khác nhau. Prototype thứ nhất:
seekg(vị_trí);
seekp(vị_trí);
Việc sử dụng các prototype này giúp làm thay đổi vị trí tuyệt đối (vị trí này tính từ đầu file). Kiểu dữ liệu của tham số này trùng với kiểu dữ liệu của hai hàm tellg() và tellp() ở trên.
Prototype thứ hai:
seekg(vị_trí, kiểu);
seekp(vị_trí, kiểu);
Việc sử dụng prototype này sẽ làm thay đổi vị trí hiện tại của con trỏ get và con trỏ put được xác định theo vị trí tương đối theo tham số vị_trí và tham số kiểu. vị_trí của một thành viên thuộc kiểu dữ liệu off_type, nó cũng là một kiểu số nguyên, nó tương ứng với vị trí của con trỏ get/set được đặt vào. Tham số kiểu là một kiểu dữ liệu seekdir, nó là một kiểu enum để xác định vị_trí của con trỏ get/put kể từ kiểu, nó có thể nhận một trong các giá trị sau đây.
vị_trí được đếm từ vị trí bắt đầu của luồng
ios::cur
vị_trí được đếm từ vị trí hiện tại của luồng
ios::end
vị_trí được đếm từ vị trí cuối của luồng
Điều này có nghĩa là hàm chồng chất hai tham số này cũng tương tự hàm một tham số, nhưng vị trí bắt đầu tính trong hàm một tham số luôn là từ vị trí đầu tiên, còn hàm hai tham số có ba vị trí có thể bắt đầu đếm – bắt đầu (ios::beg), hiện tại (ios::cur) hay cuối file (ios::end).
Bạn có thể quan sát vị dụ sau đây
Ví dụ
1. #include
2. #include
3. using namespace std;
4. int main(){
5. long begin, end;
6. ifstream myfile(“example.txt”);
7. begin = myfile.tellg();
8. myfile.seekg(0, ios::end);
9. end = myfile.tellg();
10. myfile.close();
11. cout<<”Size=”<<(end-begin)<<” bytes”;
12. return 0;
13. }
Kết quả
Size=10 bytes
Giải thích: trong chương trình trên chúng ta đang mở một file example.txt. Chúng ta đếm kích thước của file này. Khi mở file, con trỏ get sẽ đặt vào vị trí đầu file. Khi đó, dòng lệnh 7 sẽ gán giá trị khởi đầu cho biến begin (trong trường hợp này sẽ là 0). Dòng lệnh 8 sẽ đặt con trỏ get vào vị trí cuối cùng của file (vị trí 0 kể từ cuối file tính lên). Dòng lệnh 9 sẽ gán vị trí hiện tại – vị trí cuối file cho biến end. Điều đó có nghĩa là giá trị end-begin chính là kích thước của file. Bạn cũng lưu ý rằng, trong file văn bản, một kí tự tương ứng với 1 byte – đó cũng chính là quy định trong C++ (một kiểu char chiếm 1 byte). Hay nói chính xác, chương trình này đếm số kí tự trong file văn bản.
File nhị phân và Đồng bộ hóa
File nhị phân
Đối với file nhị phân, việc đọc ghi dữ liệu bằng toán tử tích trách >> và toán tử chèn << cũng như hàm getline là không có hiệu lực, bởi chúng không được định dạng theo kiểu văn bản như đối với file văn bản ở trên (không dùng phím space để tạo khoảng cách, không có kí tự xuống dòng…).
Các luồng của file gồm hai hàm thành viên để đọc và ghi dữ liệu là read và write. Hàm thành viên write là hàm thành viên của lớp ostream thừa kế từ ofstream. Và hàm read là thành viên của lớp istream thừa kế từ ifstream. Các đối tượng của lớp fstream có cả hai hàm thành viên này. Chúng có prototype như sau:
write(khối_bộ_nhớ, kích_thước);
read(khối_bộ_nhớ, kích_thước);
Ở đó, khối_bộ_nhớ là một con trỏ kiểu char (char*) và nó biểu diễn địa chỉ của một mảng các byte mà nó đọc được hoặc ghi. Biến kích_thước là một kiểu số nguyên integer, nó chỉ định số các kí tự có thể đọc/ghi lên khối bộ nhớ. Bạn có thể quan sát ví dụ sau đây
Ví dụ
#include
#include
using namespace std;
ifstream::pos_type size;
char* memblock;
int main()
{
ifstream file(“example.bin”, ios::in|ios::binary|ios::ate);
if(file.is_open()){
size = file.tellg();
memblock = new char[size];
file.seekg(0, ios::beg);
file.read(memblock, size);
file.close();
cout<<”Hoan tat !”;
//Làm việc với dữ liệu trong con trỏ memblock
delete[] memblock;
}
else cout<<”Khong mo duoc file.”;
return 0;
}
Giải thích: trong chương trình, ta mở file example.bin. Chế độ mở file để đọc (ios::in), theo kiểu file nhị phần (ios::binary), đặt con trỏ get vào cuối file (ios::ate). Sau khi mở file, hàm file.tellg() sẽ cho biết kích thước thực của file. Sau đó hàm file.seekg sẽ đặt vị trí con trỏ get vào đầu file (vị trí 0 kể từ vị trí đầu tiên) và tiến hành đọc theo khối bộ nhờ nhờ vào file.read. Sau khi hoàn tất, phương thức close được triệu gọi để kết thúc việc đọc file. Khi đó, dữ liệu từ file đã đọc vào mảng memblock. Bạn có thể bổ sung tác vụ thao tác với dữ liệu nếu muốn. Cuối cùng, con trỏ memblock sẽ bị xóa để giải phóng bộ nhớ.
Bộ đệm và Đồng bộ hóa
Khi thực thi các tác vụ đọc/ghi dữ liệu với file, chúng ta thực thi như trên nhưng thông qua một bộ đệm có kiểu dữ liệu streambuf. Bộ đệm này là một khối bộ nhớ đóng vai trò trung gian giữa các luồng và file vật lý. Ví dụ, với ofstream, mỗi thời điểm hàm put được gọi, kí tự không ghi trực tiếp lên file mà nó sẽ được ghi lên bộ đệm. Khi bộ đệm đầy, mọi dữ liệu chứa trong đó sẽ được ghi lên file (nếu đó là luồng ghi dữ liệu) hay xóa bỏ để làm rãnh bộ nhớ (nếu đó là luồng đọc dữ liệu). Tiến trình này được gọi là đồng bộ hóa và có các tình huống sau đây:
- Khi file đã đóng: trước khi đóng một file, tất cả dữ liệu trong bộ nhớ nếu chưa đầy vẫn được đồng bộ và chuẩn bị để đọc/ghi lên file.
- Khi bộ nhớ đầy: bộ đệm có kích thước giới hạn. Khi nó đầy, nó sẽ tự động đồng bộ hóa.
- Bộ điều phối: khi các bộ điều phối được sử dụng trên luồng, một tiến trình đồng bộ dứt điểm sẽ được diễn ra. Những bộ điều phối này bao gồm: flush và endl.
- Hàm thành viên sync(): nếu hàm thành viên sync() được triệu gọi, tiến trình đồng bộ hóa sẽ diễn ra. Hàm này trả về một kiểu integer (int) tương ứng với -1, nếu luồng không có bộ đệm liên kết hoặc trong trường hợp đọc/ghi thất bại. Ngược lại, nó sẽ trả về giá trị 0.
+ Kiểm tra trạng thái của các cờ hiệu :
Ví dụ trên cho ta một các thức để kiểm tra trạng thái của các cờ hiệu. Bảng sau đây sẽ liệt kê các trạng thái cờ hiệu có thể được sử dụng trong C++.
Trạng thái | Giải thích |
bad() | Nếu tác vụ đọc/ghi file bị lỗi, nó sẽ trả về giá trị true; ngược lại, nó sẽ trả về giá trị false. |
fail() | Trả về giá trị true trong trường hợp như bad(), nhưng nếu gặp lỗi về định dạng, nó cũng trả về giá trị true (ví dụ đọc số từ một file văn bản). |
eof() | Trả về giá trị true nếu file đã được đọc đến vị trí cuối cùng của file, ngược lại, trả về giá trị false. |
good() | Nó sẽ trả về giá trị true nếu bad(), fail() và eof() không phát sinh lỗi. |
+Các hàm thành viên của các lớp làm việc với File :
Con trỏ get và put
Mọi đối tượng luồng xuất nhập đều có ít nhất một con trỏ luồng:
- Luồng ifstream có con trỏ istream mà ta gọi là con trỏ get để trỏ vào phần tử có thể đọc dữ liệu.
- Luồng ofstream có con trỏ ostream mà ta gọi là con trỏ put để trỏ vào phần tử có thể ghi dữ liệu.
- Luồng fstream có cả hai con trỏ get và put để đọc và ghi dữ liệu.
Những con trỏ luồng nội tại này trỏ vào vị trí đọc và ghi với luồng có thể sử dụng các hàm thành viên sau đây:
Hàm thành viên tellg() và tellp()
Hai hàm thành viên này không có tham số và trả về giá trị của một kiểu dữ liệu dạng pos_type. Kiểu dữ liệu này bản chất là một số nguyên integer. Nó mô tả vị trí hiện tại của của con trỏ luồng get và con trỏ luồng put.
Hàm thành viên seekg() và seekp()
Những hàm thành viên này cho phép chúng ta thay đổi vị trí hiện tại của con trỏ luồng get và put. Cả hai hàm này được chồng chất với hai prototype khác nhau. Prototype thứ nhất:
seekg(vị_trí);
seekp(vị_trí);
Việc sử dụng các prototype này giúp làm thay đổi vị trí tuyệt đối (vị trí này tính từ đầu file). Kiểu dữ liệu của tham số này trùng với kiểu dữ liệu của hai hàm tellg() và tellp() ở trên.
Prototype thứ hai:
seekg(vị_trí, kiểu);
seekp(vị_trí, kiểu);
Việc sử dụng prototype này sẽ làm thay đổi vị trí hiện tại của con trỏ get và con trỏ put được xác định theo vị trí tương đối theo tham số vị_trí và tham số kiểu. vị_trí của một thành viên thuộc kiểu dữ liệu off_type, nó cũng là một kiểu số nguyên, nó tương ứng với vị trí của con trỏ get/set được đặt vào. Tham số kiểu là một kiểu dữ liệu seekdir, nó là một kiểu enum để xác định vị_trí của con trỏ get/put kể từ kiểu, nó có thể nhận một trong các giá trị sau đây.
ios::beg | vị_trí được đếm từ vị trí bắt đầu của luồng |
ios::cur | vị_trí được đếm từ vị trí hiện tại của luồng |
ios::end | vị_trí được đếm từ vị trí cuối của luồng |
Điều này có nghĩa là hàm chồng chất hai tham số này cũng tương tự hàm một tham số, nhưng vị trí bắt đầu tính trong hàm một tham số luôn là từ vị trí đầu tiên, còn hàm hai tham số có ba vị trí có thể bắt đầu đếm – bắt đầu (ios::beg), hiện tại (ios::cur) hay cuối file (ios::end).
Bạn có thể quan sát vị dụ sau đây
Ví dụ | Kết quả |
1. #include 2. #include 3. using namespace std; 4. int main(){ 5. long begin, end; 6. ifstream myfile(“example.txt”); 7. begin = myfile.tellg(); 8. myfile.seekg(0, ios::end); 9. end = myfile.tellg(); 10. myfile.close(); 11. cout<<”Size=”<<(end-begin)<<” bytes”; 12. return 0; 13. } | Size=10 bytes |
Giải thích: trong chương trình trên chúng ta đang mở một file example.txt. Chúng ta đếm kích thước của file này. Khi mở file, con trỏ get sẽ đặt vào vị trí đầu file. Khi đó, dòng lệnh 7 sẽ gán giá trị khởi đầu cho biến begin (trong trường hợp này sẽ là 0). Dòng lệnh 8 sẽ đặt con trỏ get vào vị trí cuối cùng của file (vị trí 0 kể từ cuối file tính lên). Dòng lệnh 9 sẽ gán vị trí hiện tại – vị trí cuối file cho biến end. Điều đó có nghĩa là giá trị end-begin chính là kích thước của file. Bạn cũng lưu ý rằng, trong file văn bản, một kí tự tương ứng với 1 byte – đó cũng chính là quy định trong C++ (một kiểu char chiếm 1 byte). Hay nói chính xác, chương trình này đếm số kí tự trong file văn bản.
http://dangngochoangthanh.blogspot.com
0 nhận xét:
Đăng nhận xét