Tải bản đầy đủ (.pdf) (13 trang)

All about File I/O in C++ ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (156.59 KB, 13 trang )

AllaboutFileI/OinC++
( Bài này mình lấy của anh CUONGUYEN ở trên ddth.com, bài này được viết từ năm 2002.
Mình thấy khá hay nên tổng hợp lại cho các bạn dễ tham khảo. Mình trích nguyên văn, chỉ
thêm style thôi.
Bài viết có 5 phần:
1/ Write to file 2/ Đọc từ file 3/ Quản lý luồng I/O
4/ Kiểm tra cờ trạng thái 5/ Xử lí file nhị phân 6/ Một số hàm hữu dụng
)
Tôi post bài này lên không dám qua mặt các “cao thủ”, mà chỉ để nói rằng trong diễn đ àn rất cần các
bài post này để mọi ngư ời cùng học, và t ôi hi vọng là các cao thủ sẽ post các bài của mình lên để
cho tôi học hỏi.

Bài này sẽ giới thiệu về File I/O.

1. Write To File.

Chúng ta cùng xem chương trình đầu tiên nhé:

#include <fstream.h>
void main()
{
ofstream WriteToFile(“first.txt”);
WriteToFile << “Hello World!”;
WriteToFile.close();
}

Chương trình này tạo một file “first.txt” (ở nơi cùng thư mục với file chương trình của bạn), rồi ghi
dòng “Hello World!” vào file.

Hãy đi từng dòng nhé:


#include <fstream.h> - Thư viện để sử dụng các hàm File I/O.

ofstream WriteToFile(“first.txt”):
ofstream là một lớp. Dòng này tạo một đối tượng thể hiện lớp ofstream là WriteToFile (hoặc một tên
bất kỳ), dùng hàm contructor với tham số “first.txt”. Hàm này sẽ tạo ra một file với tên là “first.txt”.

WriteToFile << “Hello World!”: ghi chuỗi “Hello World!” vào file.

WriteToFile.close(): đóng file lại. Mỗi khi bạn mở một file, sau đó bạn phải đóng nó lại.

2. Đọc từ File.


Chương trình.

#include <fstream.h>
void main(){
ifstream OpenFile("first.txt");
char ch;
while(!OpenFile.eof())
{
OpenFile.get(ch);
cout << ch;
}
OpenFile.close();
}

Chương trình này dùng cách đọc từng ký tự (còn có cách khác là đọc từng từ (word) và đọc từng
dòng (line) - sẽ tham khảo sau).


ifstream OpenFile(“first.txt”) – Tạo một đối tượng thể hiện lớp ifstream tên là OpenFile (có thể dùng
tên khác tuỳ ý). Hàm contructor với tham số “first.txt”, đây là file mà chúng ta đã tạo ở mục trên.
Hàm này sẽ mở file “first.txt” để đọc.

char ch: dòng này tôi biết rằng các bạn đã quá quen thuộc.

while(!OpenFile.eof()) - hàm eof() của lớp ifstream. Hàm eof() trả về giá trị 0 khi chưa kết thúc file,
ngược lại là 1.

OpenFile.get(ch); - get(char &ch) là một hàm của lớp ifstream, hàm này sẽ đọc từng ký tự của file và
gán cho biến ch. Sau đó sẽ chỉ đến ký tự tiếp theo (do inside-pointer)

Vòng lặp while sẽ lặp cho tới khi kết thúc file, mỗi lần lặp sẽ đọc một ký tự và gán cho biến ch. Sau
đó đưa ra màn h ình ký tự đó:

cout<<ch;

Vòng lặp tiếp theo sẽ đọc ký tự tiếp theo sau ký tự trước (do inside-pointer: điều này sẽ được giải
thích ở phần sau). Do đó khi chạy chương trình, sẽ xuất hiện trên màn hình dòng chữ:

“Hello World!”

3. Quản lý Iuồng I/O.


Trong phần này chúng ta sẽ học về một số hàm hữu dụng.

Phần trước chúng ta đã tạo một file bằng lệnh:

ofstream File(“filename.txt”);


Chúng ta có một cách khác đó là sử dụng hàm open():

ofstream File;
File.open(“finename.txt”);

Hàm open() nguyên dạng:

void open(char *filename, [int open_mode]);

trong đó tham số open_mode chỉ ra phương thức mở file. Nó có thể có các giá trị sau:

+ ios::in -> mở file để đọc.
+ ios::out -> mở file để ghi.
+ ios::app -> mở file để ghi vào cuối file. Nó gọi ios::out (?).
+ ios::ate -> mở file để ghi vào cuối. Nó không gọi ios::out (?).
+ ios::trunc -> xoá tất cả nội dung đã có.
+ ios::nocreate -> nếu file chưa tồn tại, sẽ không mở được.
+ ios::noreplace -> nếu file đã tồn tại, cố gắng mở sẽ gây lỗi.
+ ios::binary -> mở file binary.

Ví dụ 1:

#include <fstream.h>
void main()
{
ofstream WriteToFile(“first.txt”, ios::ate);
WriteToFile<<”\nI love you”;
WriteToFile.close();
}


Kết quả là file “first.txt” (phần trước) có nội dung là:

Hello World!
I love you

Nếu không có tham số ios::ate thì nội dung của file lúc trước sẽ bị xóa.

Ví dụ 2:
Nếu chưa có file “non_exit.txt”.

#include <fstream.h>
void main()
{
ofstream File(“non_exit.txt”, ios::nocreate);
if(!File) {
cout<<”Error openning.”;
exit(1);
}
File.close();
}

Kết quả: “Error openning.” và không tạo file trong thư mục của bạn. Nếu không có tham số
ios::nocreate thì vẫn vô tư, nghĩa là không có dòng thông báo lỗi và vẫn tạo ra file “non_exit.txt”.

Ví dụ 3:
#include<fstream.h>
int main()
{
ifstream File(“first.txt”, ios::noreplace);

if(!File) {
cout<<”Error!”;
exit(1);
}
File.close();
return 0;
}

Kết quả: “Error!”, vì file “first.txt” đã tồn tại. Tham số ios::noreplace không cho phép mở file đã tồn
tại.
Nếu bạn muốn có nhiều phương thức mở bạn dùng toán tử OR (|):

ios::ate | ios::binary

Sử dụng open_mode, chúng ta có thể vừa mở file để đọc và để ghi. Ví dụ:

#include <fstream.h>

void main()
{
fstream File("second.txt",ios::in | ios::out);
File << "Hi! I’m there.";
char ch;
File.seekg(ios::beg);
while(!File.eof())
{
File.get(ch);
cout <<ch;
}
cout<<endl;

File.close();
}

Có cái gì mới mẻ ở đây ấy nhỉ. Okay, chúng ta sẽ hiểu ngay thôi.

fstream File(“test.txt”, ios::in | ios::out); - vì mở file vừa để đọc và ghi nên chúng ta tạo một đối
tượng thuộc lớp fstream (chứ không phải ofstream-để ghi hay ifstream để đọc).

File.seekg (ios::beg); - A đây rồi, cái này có vẻ hơi mới mẻ nhỉ (tất nhiên là với người bắt đầu học).
Để xem tại sao lại phải sử dụng “nó” chúng ta hãy xem khối lệnh:
while(!OpenFile.eof())
{
OpenFile.get(ch);
cout << ch;
}
Khối lệnh này chắc hẳn bạn đã biết. Hàm get(ch) sẽ đọc một kí tự của file và gán cho biến ch. Vòng
lặp sẽ kết thúc khi đến cuối file. Để vòng lặp “biết” được khi nào thì kết thúc file thì, khi đọc file có
một “con trỏ trong” (inside-pointer). Sau khi get(ch) thực hiện việc gán cho ch kí tự hiện hành thì
“inside-pointer” sẽ chỉ đến kí tự tiếp theo. Cứ thế, đến lần lặp sau ch sẽ nhận được giá trị tiếp theo
cho đến khi kết thúc file.

Quay trở lại hàm seekg(). Lý do phải sử dụng hàm này vì sau câu lệnh:

File<<”Hi! I’m there”;
thì “inside-pointer” sẽ trỏ đến cuối file. Vì vậy phải dùng câu lệnh:

File.seekg(ios::beg);

để đưa “inside-pointer” về đầu file. Bạn có thể sử dụng các tham số cho hàm seekg() như sau:
ios::beg – đưa “inside-pointer” về đầu file (có giá trị là 0).

ios::end - đưa “inside-pointer” về cuối file. Nhưng tại sao tôi thấy tham số này luôn chỉ đến kí tự thứ
3 thế nhỉ (giá trị 2)?
Hoặc bạn có thể dùng:

File.seekg(4); -> “inside-pointer” chỉ đến kí tự thứ 4 kể từ đầu file (ký tự đầu là 0).
File.seekg(-5,ios::end); -> đưa “inside-pointer” đến cuối file sau đó quay lại 5 kí tự.

Ví dụ:
#include<fstream.h>
main()
{
ifstream File(“second.txt”);
char ch;
File.seekg(-5, ios:end);
File.get(ch);
cout<<ch;
File.close();
}

Nội dung file “second.txt” là “Hi! I’m there.”
Kết quả được “h”.

Như trên đã nói, ngoài cách đọc từng char, ta có thể đọc từng word, hay từng line.
Ví dụ:
#include<fstream.h>
void main
{
ifstream File(“first.txt”, ios::in);
char str[30];//lưu trữ từng từ vào str.
while(!File.eof())

{
File >> str;
cout << str<<” “;
}
File.close();
}

File>>str sẽ đọc từng từ và gán cho str. Kết quả ta sẽ được “Hello World! I love you.” (không xuống
dòng-đây là nhược điểm của phương pháp này).

Bạn có thể đọc từng line. Ví dụ:
#include<fstream.h>
void main()
{
ifstream File(“first.txt”);
char line[100]; //lưu trữ toàn bộ dòng vào biến này
while(!File.eof())
{
File.getline(line,100);
cout << line << endl;
}
File.close();
}

Kết quả:
Hello World!
I love you.

Như vậy, một điều khuyên cho các bạn đó là sử dụng cách đọc từng char, hoặc từng line. Vậy ta có
thể đọc file theo 3 cách:

- Đọc từng char: File.get(ch);
- Đọc từng word: File>>ch;
- Đọc từng line: File.getline(ch,dimension);
Bây giờ chúng ta sẽ "check" xem file có mở được hay không:
Cách 1:
ofstream (ifstream) File("somefile.txt");
if(!File) {

}
Cách này đã được sử dụng ở một số ví dụ trước.
Cách 2: Sử dụng hàm fail():
ofstream File("somefile.txt");
if(File.fail())
{

}
Hàm fail() trả về giá trị 0 nếu có lỗi (không mở được file) hay 1 nếu không có lỗi.

Để kiểm tra xem file đã được mở chưa ta dùng hàm is_open(). Hàm trả về 0 nếu file chưa được mở,
1 nếu file đã được mở. Ví dụ:

ofstream File;
File.open("file1.txt");
cout << File1.is_open();

sẽ cho giá trị 1.


4. Kiểm tra cờ trạng thái I/O (I/O status-flag).




Hệ thống I/O trong C++ nắm giữ các thông tin về kết quả của các toán tử I/O. Trạng thái hiện hành
được lưu trữ trong một đối tượng kiểu io_state (tương tự open_mode) với những giá trị sau:
+ ios::goodbit: không có lỗi.
+ ios::eofbit: tới cuối file.
+ ios::failbit: lỗi không gây hại (non-fatal).
+ ios::badbit: lỗi gây hại (fatal).

Có hai cách để nhận được thông tin về trạng thái I/O. Cách thứ nhất là gọi hàm rdstate(). Hàm này
trả về trạng thái của cờ lỗi. Ví dụ, hàm rdstate() sẽ trả về giá trị ios::goobit nếu không có lỗi Cách
thứ hai là sử dụng một trong các hàm sau:

bool bad() -> 1 nếu có lỗi badbit.
bool eof() -> 1 nếu đến cuối file.
bool fail() ->1 nếu có lỗi failbit.
bool good() ->1 nếu không có lỗi.

Ví dụ:
ofstream File("somefile.txt");
if(File.bad()==1) {

}

Khi một lỗi xảy ra, bạn có thể xoá bỏ lỗi đó (thiết lập lại cờ trạng thái). Để làm việc này bạn dùng hàm
clear(arg), với arg là cờ trạng thái mà bạn muốn thiết lập khi có lỗi.

Các ví dụ về cờ trạng thái:
Ví dụ 1: Sử dụng hàm rdstate().
ifstream File("somefile.txt");

if(File.rdstate() == ios::eofbit)
cout << "End of file!\n";
if(File.rdstate() == ios::badbit)
cout << "Fatal I/O error!\n";
if(File.rdstate() == ios::failbit)
cout << "Non-fatal I/O error!\n";
if(File.rdstate() == ios::goodbit)
cout << "No errors!\n";

Ví dụ 2: Sử dụng hàm clear().

#include <fstream.h>
void main()
{
ofstream File("love.txt"); //tạo file love.txt
File.close();
//Việc mở file dưới đây sẽ gây lỗi vì sử dụng open_mode là ios::noreplace
ofstream Test("love.txt",ios::noreplace);
//Lỗi này là lỗi ios::failbit.
if(Test.rdstate() == ios::failbit)
cout << "Error !\n";
Test.clear(ios::goodbit); //Đặt flag sang trạng thái goodbit.
if(Test.rdstate() == ios::goodbit)
cout << "Fine!\n";
Test.clear(ios::eofbit); //Đặt sang trạng thái eofbit.
if(Test.rdstate() == ios::eofbit)
cout << "EOF!\n";
Test.close();
}


5. Xử lý file nhị phân

Mặc dù các file với định dạng text rất hữu dụng, nhưng đôi khi bạn cần làm việc với các file nhị phân.
Các hàm để ghi/đọc với các file này là get() và put(). Để đọc một byte, sử dụng hàm get() và để ghi
một byte sử dụng hàm put(). Cả hai hàm này đều nhận một đối số. Lưu ý là các hàm này chỉ ghi/đọc
được một byte, nghĩa là một ký tự.
Nếu bạn muốn đọc/ghi một khối dữ liệu, bạn có thể sử dụng các hàm read() và write(). Nguyên mẫu
của chúng là:

istream &read(char *buf, streamsize num);
ostream &write(const char *buf, streamsize num);

Với hàm read(), buf nên là một mảng ký tự mà khối dữ liệu đọc sẽ được đặt vào.
Với hàm write(), buf là một mảng ký tự,là dữ liệu mà bạn muốn ghi vào file.
Với cả hai hàm num là một số xác định dữ liệu được đọc/ghi.
Nếu bạn đi đến cuối file, trước khi bạn đọc "num" ký tự, bạn có thể thấy bao nhiêu ký tự đọc được
bằng cách dùng hàm gcount().

Ví dụ 1: Sử dụng hàm put() và get().
#include <fstream.h>
void main()
{
fstream File("iloveyou.txt",ios::out | ios::in | ios::binary);
char ch;
ch='o';
File.put(ch); //Đưa nội dung của ch vào file.
File.seekg(ios::beg); //đến đầu file.
File.get(ch); //đọc một ký tự
cout << ch << endl;
File.close();

}

Ví dụ 2: Sử dụng read() and write()

#include <fstream.h>
#include <string.h>
void main()
{
fstream File("test_file.txt",ios::out | ios::in | ios::binary);
char arr[13];
strcpy(arr,"Hello World!"); //copy "Hello World!" vào arr
File.write(arr,5); //ghi 5 ký tự đầu vào file- "Hello"
File.seekg(ios::beg); //trở về đầu file
static char read_array[10];
File.read(read_array,3); //Đọc 3 ký tự - "Hel"
cout << read_array << endl;
File.close();
}



6. Một số hàm hữu dụng.

+ tellg() – Trả về một giá trị nguyên, cho biết vị trí hiện tại của inside-pointer. Hàm này dùng khi đọc
file. Ví dụ:
#include <fstream.h>
void main()
{
ofstream File("test.txt");
File<<"Hello";

File.close();
ifstream File1("test.txt");
char arr[10];
File1.read(arr,10);
cout << File1.tellg() << endl; //cho giá trị 5.
File1.close();
}
+ tellp() – Giống tellg() nhưng được sử dụng khi ghi vào file.
+ seekp() – Giống seekg(), được sử dụng khi ghi vào file.
+ ignore() – Sử dụng khi đọc file. Nếu bạn muốn "ignore" một số ký tự, hãy sử dụng hàm này. Thực
ra, bạn có thể sử dụng hàm seekg() thay thế, nhưng hàm ignore() có một ưu điểm, bạnc có thể đặc
tả một quy định giới hạn, nơi hàm ignore() sẽ kết thúc. Dạng hàm ignore() là:

istream& ignore( int nCount, delimiter );

Trong đó nCount là số lượng ký tự sẽ được bỏ qua và delimiter là giới hạn nơi hàm ignore() kết thúc.
Nó có thể là EOF. Ví dụ:
#include <fstream.h>
void main()
{
//Ở trên chúng ta đã có "Hello World" trong file test_file.txt
ifstream File("test_file.txt");
static char arr[10];
//Dừng hàm ignore() nếu gặp ký tự "l"
File.ignore(6,'l');
File.read(arr,10);
cout << arr << endl; //cho "lo World!"
File.close();
}


+ getline() – Hàm này được sử dụng để đọc từng line, nhưng nó còn được thiết lập để ngừng đọc
nếu nó gặp một ký tự nào đó. Để làm việc này sử dụng dạng sau:

getline(array,array_size,delim);

Trong đó delim là ký tự dùng để kết thúc việc đọc.

Ví dụ:
#include <fstream.h>
void main()
{
//Nhớ là chúng ta đã có "Hello World" trong file "test.txt"
ifstream File("test_file.txt");
static char arr[10];
File.getline(arr,10,'o');// Đọc cho tới khi gặp ký tự 'o'
cout << arr << endl; //Cho "Hell"
File.close();
}
+ peek() – Hàm này sẽ cho mã ASCII của ký tự tiếp theo trong một luồng file input. Nhưng nó không
dịch chuyển inside-pointer. Khác với hàm get() là cho ký tự tiếp theo và dịch chuyển inside-pointer.
Nếu sử dụng hàm này hai lần liền sẽ được cùng một ký tự. Ví dụ:
#include <fstream.h>
void main()
{
ifstream File("test_file.txt");
char ch;
File.get(ch);
cout << ch << endl; //cho "H"
cout << char(File.peek()) << endl; //hiển thị "e"
cout << char(File.peek()) << endl; //hiển thị "e"

File.get(ch);
cout << ch << endl; //hiển thị "e"
File.close();
}

+ _unlink() – Xoá toàn bộ file. Để sử dụng hàm này hãy "#include<io.h>" trong chương trình của bạn.
Ví dụ:
#include <fstream.h>
#include <io.h>
void main()
{
ofstream File;
File.open("delete_test.txt"); //tạo file delete_test.txt
File.close();
_unlink("delete_test.txt"); //xoá file delete_test.txt
File.open("delete_test.txt",ios::nocreate);//mở file đã xoá với open_mode là ios::nocreate sẽ gây
//lỗi. Lỗi này là ios::failbit
if(File.rdstate() == ios::failbit)
cout << "Error !\n";
File.close();
}
+ putback() –Hàm này sẽ cho ký tự đọc lần cuối cùng và sẽ dịch chuyển inside-pointer về trước một
ký tự.
Ví dụ:
#include <fstream.h>
void main()
{
ifstream File("test_file.txt");
char ch;
File.get(ch);

cout << ch << endl; // display "H", dịch chuyển inside-pointer sang "e"
File.putback(ch); // đọc ký tự lần cuối "H", dịch chuyển inside-pointer về ký tự "H"
cout << ch << endl; // display "H"
File.get(ch);
cout << ch << endl; // display "H"
File.close();
}

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×