C++ Bài 11: Đọc Ghi Dữ Liệu – Xử Lý File

Kỹ thuật đọc ghi dữ liệu  c++

– Được ứng dụng rộng rãi và là một kỹ thuật không thể thiếu được trong các ứng dụng lập trình từ môi trường console đến môi trường windows, cơ sở dữ liệu và hệ thống.

– File thường được sử dụng cho các mục đích như : lưu trữ dữ liệu, lưu trữ nhật ký hoạt đông, lưu trữ cấu hình phần mềm. => Do đó nắm vững trong tay kỹ thuật xử lý file bằng ngôn ngữ lập trình C++ là một điều vô cùng quan trọng.

I. KIẾN THỨC CƠ BẢN VÊ ĐỌC GHI DỮ LIỆU TRONG LẬP TRÌNH C++.

A. ghi file trong c++.

1. Kiểm tra sự tồn tại của 1 file.

– Biết được tên file. – Sử dụng đường dẫn tương đối nếu chỉ ở trong folder chứa file source của project. – Và sử dụng đường dẫn tuyệt đối với file ở bất cứ chỗ nào – Không phân biệt chữ hoa chữ thường trong tên file – Sử dụng loại fstream của thư viện tiêu chuẩn STL.

#include <fstream> #include <iostream> #include <conio.h> using namespace std; bool CheckFileExisting() { bool is_exist = true; fstream data_file; data_file.open("value.txt", ios::in); bool ret = data_file.fail(); if (ret == true) { is_exist = false; } data_file.close(); return is_exist; }
2. Ghi data vào 1 file. Nếu file chưa có thì sẽ thực hiện tạo file.

– Có thể sử dụng xử lý kiểm tra file ở trên hoặc không cũng không sao – Nếu file đã có thì xóa nội dung trong nó đi và ghi mới vào – Nếu file chưa có thì sẽ tạo mới – Vẫn sử dụng fstream.

#include <fstream> #include <iostream> #include <conio.h> using namespace std; void WriteFileMode(char* file_name) { if (file_name != NULL) { fstream data_file; data_file.open(file_name, ios::out); data_file << "Welcome to blog: phattrienphanmem123az.com \n"; data_file << "Chu de hoc lap trinh c++ co ban! \n"; data_file.close(); } } void main() { WriteFileMode("demo.txt"); return; }

Trong trường file tồn tại và muốn ghi tiếp nối dung vào nội dung đã có. – Ta sử dụng thêm ios::app sau ios::out – dataFile.open(“demo.txt”, ios::out | ios::app);

3. Ghi dữ liệu vào file sử dụng hàm put.

Là một hàm trái ngược với hàm get. Hàm get để đọc 1 ký tự từ file ra còn hàm put thì sử dụng để ghi 1 ký tự vào file. Xem mục 6 để hiểu thêm về hàm get.

B. Đọc File trong c++

4. Đọc dữ liệu từ file cách số 1 : Sử dụng toán tử  >>

Vẫn sử dụng fstream. Không đọc các ký tự như là space, \n, tab.

Chỉ đọc dữ liệu chuỗi có trong file. Ví dụ chúng ta viết như sau : Tôi yêu em. Tôiyêu em Tôi yêu em Thì cứ mỗi lần đọc bằng >> nó sẽ chỉ lấy các chuỗi: tôi , yêu, em. Không lấy space hay các ký tự khác . Code:

#include <fstream> #include <iostream> #include <conio.h> using namespace std; void ReadFileModeOpen(char* fileName) { char input[100]; fstream fsFile; fsFile.open(fileName, ios::in); if (fsFile == 0) { cout << "Cannot read file!"; } else { while (fsFile >> input) { cout << input; } } fsFile.close(); } void main() { ReadFileModeOpen("demo.txt"); return; }

Note: Input là một mảng. Mỗi lần đọc input sẽ nhận chuỗi đọc ra và sau đó lại bị thay thế bởi chuỗi kế tiếp. Sử dụng cách này có nhiều hạn chế. Chỉ đọc được chuỗi bít liên tục hoặc đọc những chuỗi bít cách nhau bởi ký tự. Khó xác định được kỹ thước chuỗi bít lấy ra là bao nhiều để cấp phát vùng nhớ cho phù hợp.

5. Đọc file sử dụng hàm getline.

– Sử dụng phương thức này thì sẽ chỉ phân biệt ký tự \n hoặc 1 ký tự ta quy định -Tức là nó không đọc ký tự \n mà chỉ đọc các chuỗi. – Ưu điểm hơn so với cách trên vì nó đọc được cả space,  tab.. – Nhược điểm, vẫn chưa xác định được số ký tự cho từng chuỗi đọc để cấp phát động cho hợp lý. – Sử dụng cho mục đích đọc từng line của một file Code:

#include <fstream> #include <iostream> #include <conio.h> using namespace std; void ReadFileModeOpen(char* fileName) { char input[100]; fstream fsFile; fsFile.open(fileName, ios::in); if (fsFile == 0) //VS2015 co thể bị lỗi đoạn này, thay thế bằng if (!fsFile.is_open()) { cout << "Cannot read file!"; } else { while (!fsFile.eof()) { fsFile.getline(input, 100); cout << input; } } fsFile.close(); } void main() { ReadFileModeOpen("demo.txt"); return; }

Note: đoạn code trên sử dụng mặc định ký tự \n  (xuống dòng cho mỗi lần getline).

Sử dụng câu lệnh sau để lựa chọn ký tự khác cho mỗi lần get line.

while(!file_data.eof())

{     file_data.getline(input, 100, ‘@’);     cout << input; }

6. Đọc  file Sử dụng hàm get

– Hàm này thực hiện đọc từng ký tự trong file, bất kể là ký tự gì. Do đó mỗi khi đọc được 1 ký tự ta cần lưu nó và một phần tử của mảng ký tự hay chuỗi ký tự. – Hàm file_data.eof() sử dụng đi kèm với hàm get(ch) thì nó sẽ chạy từng ký tự đến khi nào gặp ký tự kết thúc xâu thì dừng – Còn đi với hàm getline thì nó ko chạy từng xâu ký tự mà chạy từng line đến line cuối thì nó dừng lại Code:

– Nhược điểm : Vẫn chưa xác định được kích thước data cần lấy ra để cấp phát động cho vùng nhớ.

#include <fstream> #include <iostream> #include <conio.h> using namespace std; void ReadFileModeOpen(char* fileName) { char ch; char input[100]; fstream fsFile; fsFile.open(fileName, ios::in); if (fsFile == 0) { cout << "Cannot read file!"; } else { int i = 0; while (!fsFile.eof()) { fsFile.get(ch); input[i] = ch; i++; } } fsFile.close(); } void main() { ReadFileModeOpen("demo.txt"); return; }
7. Phần mở rộng.
* Tìm hiểu về các cờ trạng thái kiểm tra.

– Bad() : Trả lại giá trị true nếu như việc đọc hay việc ghi một file là thất bại. – Fail() :  Giống như trường hợp của bad(). Nhưng thường được dùng khi đọc sai kiểu dữ liệu. – Eof() : Trả lại giá trị true khi file được mở được đọc đến ký tự cuối cùng. Một cách nhận biết kết thúc file. – Good() : Hàm chung nhất trong cờ kiểm tra. Kết quả của nó phụ thuộc và kết quả hàm đi trước. – Clear() : Là hàm đưa các hàm trạng thái ở trên về ban đầu, tức là reset lại.

* Vào và Ra với con trỏ luồng.
– Tellg() và Tellp()

   Là hai hàm không có tham số đầu vào và nó trả lại một giá trị có kiểu dữ liệu pos_type, là một kiểu dữ liệu nguyên thể hiện cho vị trí hiện tại của con trỏ luồng nhận dữ liệu (Tellg) và con trỏ luồng ghi dữ liệu (Tellp())

– Seekg() và Seekp():

Hai hàm này cho phép chúng ta để thay đổi vị trí của 2 con trỏ vào và ra. Cả hai đều được quá tải với hai thuộc tính khác nhau. Quá tải ở đây có nghĩa là đầu vào của nó có thể truyền được nhiều tham số tùy ý người sử dụng.

Ví dụ. seekg ( position ); seekp ( position ); seekg ( offset, direction ); seekp ( offset, direction );

Hai hàm này được sử dụng hữu ích cho việc đọc một khối lượng dữ liệu file dựa vào vị trí từ a đến b Ví dụ chúng ta có thể đặt ví trí con trỏ ở đầu file, một vị trí bất kỳ ở giữa file hay là từ cuối file.

Với 3 cờ sau đây: ios::beg ios::cur ios::end

Xét ví dụ sau:

#include <fstream> #include <iostream> #include <conio.h> using namespace std; void main() { long begin = 0; long end = 0; ifstream my_file ("sample.txt"); begin = my_file.tellg(); my_file.seekg(0, ios::end); end = my_file.tellg(); long size = end - begin; cout << "size of file is: " << size << "byte"; my_file.close(); return; }

con trỏ file được nằm tại ví trí đầu tiên của file và chúng ta lấy được vị trí này thông qua hàm tellg() Di chuyển con trỏ file tới cuối cùng của file bằng hàm seekg() với cờ std::ios::end. Lấy vị trí của con trỏ lúc này khi nó nằm ở cuối file xem vị trí của nó là byte thứ bao nhiêu trong file.

Bằng cách sử dụng hàm tellg() kích thước của file sẽ được tính bằng = end – begin với đơn vị là byte. Thường 1 byte = 1 ký tự.

* Đọc File nhị phân trong C++.

File text bình thường là các ký tự nhị phân đã được mã hóa dạng mã ascii với 8bit = 1 byte = 1 ký tự. Do đó chúng ta có thể mở file và đọc được nội dung.

Nhưng file nhị phân thì khác, các ký tự ở dạng số nhị phân và chúng ta không thể đọc được. Dưới đây minh họa cho một file nhị phân.

clip_image004 Dữ liệu file nhị phân đang thể hiện ở dạng mã máy.

=> Do đó ý tượng cho việc đọc file nhị phân sẽ là đọc theo số lượng byte. Hai hàm chuyên dùng để đọc file nhị phân trong C++ đó là hai hàm readwrite của hai lớp Ostream và istream.

Thuộc tính của hai hàm như sau: Write (memory_block, size) Read(memory_block, size) Memory_block ở đây là một con trỏ kiểu char, được sử dụng để lấy dữ liệu đọc ra từ file. Hoặc chứa dữ liệu ghi vào file.

Ví dụ: std::ifstream file (“MyFile.STL”, std::ios::in|std::ios::binary|std::ios::ate); if (file.is_open())

{     size = file.tellg();     memblock = new char [size];     file.seekg (0, std::ios::beg);     file.read (memblock, size);     file.close(); } Trong ví dụ trên, std::ios::ate đã đưa con trỏ file về vị trí cuối cùng của file.

Do đó size = vị trí byte cuối cùng file Memblock được lấy dữ liệu ra từ file sau khi đã cấp phát tương số byte.
* Một số hàm đọc file khác.
Ngoài việc sử dụng fstream để làm việc với file, chúng ta còn có thể sử dụng lớp FILE để làm việc với file. Khi đó 1 số hàm đặc biệt khác được sử dụng để đọc file. #include <iostream> #include <conio.h> using namespace std; void main() { FILE* pFile; char my_string[100]; pFile = fopen("file.txt", "r"); if (pFile == NULL) { perror("Error open file"); } else { if (fgets(my_string, 100, pFile) != NULL) { puts(my_string); } fclose(pFile); } return; }

Lưu

Lưu

Lưu

Lưu

Lưu

Lưu

Lưu

Từ khóa » Cách Dùng Fstream