Nội dung bài viết
STDIO Kiến thức về file là một trong những kiến thức quan trọng đối với các lập trình viên. Bài viết này trình bày chi tiết về 2 loại file là file nhị phân và file text, cũng như các kỹ thuật thao tác với file thông qua thư viện fstream.

Giới thiệu

Kiến thức về file là một trong những kiến thức quan trọng đối với các lập trình viên. Trong bài viết trước, chúng ta đã tìm hiểu khái niệm về file cũng như một số định dạng file thông dụng. Bài viết này xin được trình bày chi tiết về 2 loại file là file nhị phânfile text, cũng như các kỹ thuật thao tác với file thông qua thư viện fstream.

Tiền đề bài viết

Bài viết nằm trong chương trình LẬP TRÌNH C++.

Đối tượng hướng đến

Bài viết hướng đến các lập trình viên mới, đang tìm hiểu ngôn ngữ lập trình C++. Nội dung trong bài viết không yêu cầu người đọc có kiến thức sâu về ngôn ngữ này.

File nhị phân

Khái niệm

File nhị phân (hay binary file) là một tập tin máy tính, có thể chứa bất kỳ dạng dữ liệu nào, được mã hóa dưới dạng nhị phân để lưu trữ trong máy tính.

Cấu trúc

  • Tập tin nhị phân thường được coi là một chuỗi các byte (các số nhị phân được nhóm theo nhóm cứ 8 bit thành 1 byte).
  • Một vài tập tin nhị phân có phần header, chứa thông tin để quy định cấu trúc dữ liệu trong file nhị phân đó.

Ứng dụng

Máy tính của chúng ta chỉ hiểu được mã máy (machine code còn gọi là machine language), do đó, mọi dữ liệu muốn được máy tính “hiểu”, đều phải chuyển về dạng nhị phân. Các file nhị phân mà chúng ta hay gặp nhất là dạng execute file (định dạng .exe trên windows…).

File nhị phân có thể lưu trữ được nhiều dạng dữ liệu như file txt, file nhạc, file ảnh…

File văn bản

Khái niệm

File văn bản là một tên gọi chung cho các dạng file lưu trữ dữ liệu dưới dạng ký tự. Trong phạm vi bài viết này, chúng ta chỉ tìm hiểu về file text (định dạng txt).

Cấu trúc

File văn bản (text) có cấu trúc gồm nhiều record. Mỗi một record trong file text được kết thúc bằng ký tự newline character (là ký tự \n với mã Unicode và mã ASCII).

Ứng dụng

File văn bản dùng để lưu trữ dữ liệu dạng ký tự, một số định dạng file văn bản có thể đọc dữ liệu bằng mắt thường như là file txt, file doc, file docx.

Thao tác file với fstream

Thao tác với file gồm 3 giai đoạn: MỞ FILE → ĐỌC HOẶC GHI DỮ LIỆU → ĐÓNG FILE.

Mở file

Để sử dụng được thư viện fstream, ta phải include thư viện fstream và using namespace std;

#include <fstream>
using namespace std;

Điều đầu tiên, ta tạo ra một đối tượng fstream. Ta sẽ thao tác với file thông qua đối tượng đó.

fstream f;

Để mở một file, ta dùng phương thức open sau:

f.open(filePath, mod);

Trong đó:

  • filePath có kiểu dữ liệu là const char*, là đường dẫn đến file cần mở.
  • mod là chế độ mở file. Chúng ta có một số chế độ như sau:
MOB CHỨC NĂNG
ios::in Mở file để đọc.
ios::out Mở file có sẵn để ghi
ios::binary Mở file ở chế độ nhị phân.
ios:ate Mở file và đặt con trỏ file vào cuối file.
ios::app Mở file và ghi dữ liệu vào cuối file. Nếu file không tồn tại thì tạo file mới.
ios::trunc Chế độ mở file, xóa bỏ hoàn toàn nội dung trong file được mở.

Đọc và ghi dữ liệu với định dạng file nhị phân

Khi mở file mà không ghi rõ chế độ mở file, trình biên dịch sẽ chuyển về chế độ mở file text. Vì vậy, khi muốn mở ở chế độ binary, ta cần phải ghi rõ ràng mod là ios::binary. Việc mở file dưới chế độ binary có nghĩa là chúng ta sẽ đọc thông tin theo dạng binary file. Chúng ta sẽ sử dụng hàm write read để đọc và ghi file dưới dạng binary.

Trường hợp đọc dữ liệu từ file

f.read(address, size);

Trong đó:

  • address: Kiểu dữ liệu char*, là địa chỉ mà dữ liệu sẽ lưu vào sau khi đọc lên.
  • size: Kiểu dữ liệu int, là số lượng byte trong bộ nhớ được đọc vào từ file.

Trường hợp ghi dữ liệu vào file

f.write(address, size);

Trong đó:

  • adress: Kiểu dữ liệu char*, là địa chỉ vùng nhớ của dữ liệu được lưu vào file.
  • size: Kiểu dữ liệu int, là số byte vùng nhớ mà nó sẽ ghi.

LƯU Ý

  • size là kích thước mà vùng nhớ chứa dữ liệu của quá trình đọc hay ghi.

Ví dụ ta có đoạn mã sau:

#include <fstream>

using namespace std;

int main()
{
	char data[100];

	fstream f;
	f.open("text.txt", ios::in | ios::binary);
	if (!f)
	return 1;

	f.read(data, sizeof(data));
	f.close();

	return 0;
}

Đọc và ghi dữ liệu với định dạng file text

Một điều khá may mắn là việc đọc và ghi dữ liệu với định dạng file rất thông dụng – file text lại khá dễ dàng.

Sau khi mở tệp tin ta sẽ tiến hành đọc và ghi file bằng operator >><<.

Đọc file

f >> data;

Trong đó:

  • f:  Kiểu dữ liệu fstream, là tên biến file.
  • data: là tên biến lưu trữ dữ liệu.

LƯU Ý

  • data: là tên biến để lưu trữ dữ liệu. Có thể có các kiểu như int, float, long, char… (nhóm kiểu dữ liệu primitive).
  • Khi dữ liệu được đọc có kiểu khác với biến dữ liệu được lưu trữ.
    • Biến lưu trữ dữ liệu kiểu số không đọc vào kiểu kí tự.
    • Biến lưu trữ dữ liệu kiểu số được tự động chuyển kiểu qua lại giữa các kiểu (float sang int, int sang float) bằng cơ chế chuyển kiểu ngầm định.

Ghi file

f << data;

Trong đó:

  • f: là tên biến file.
  • data: tên biến dữ liệu chứa data cần ghi vào file.

LƯU Ý

  • Thư viện fstream hỗ trợ ghi dữ liệu char, int, long.., (nhóm dữ liệu primitive). Tuy nhiên lại không hỗ trợ ghi kiểu dữ liệu mở rộng (struct, class…).

Ngoài việc sử dụng operator, bạn có thể tìm hiểu thêm việc sử dụng hàm get và hàm put để lấy thông tin từ file. Chúng ta sẽ đi sâu tìm hiểu về hai hàm này trong các bài viết khác của STDIO.

Đóng file

Sau khi thao tác với file, ta sẽ tiến hành đóng file bằng lệnh:

f.close()

Việc đóng file sẽ giúp chúng ta bảo toàn được dữ liệu đang tiến hành lưu trữ. Đồng thời tránh khỏi một số lỗi không đáng có.

Các ví dụ

Đọc dữ liệu

Chúng ta sẽ thực hiện đọc dữ liệu từ 2 file text, và đọc dữ liệu có các kiểu khác nhau trong cùng một file text.

Trong ví dụ này, tôi có 2 file text: file text IntroUniversity lưu trữ tên trường đại học của sinh viên, và file text StorageStudentInfo lưu thông tin sinh viên học tại trường đó, gồm tên và mã số sinh viên.

Dữ liệu trong file IntroUniversity:

University of Information Technology

Dữ liệu trong file StorageStudentInfo

Trung	10
Nam	    4
Bac		8

Mã nguồn thực thi:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void PrintStudentInfo(string StudentName[], int StudentID[], int n) // Với n là số sinh viên.
{
	for (int i = 0; i < n; ++i)
	{
		cout << StudentID[i] << "\t" << StudentName[i] << endl;
	}
}

int main()
{
	fstream 	fs;
	string	name_of_university;
	string	name_of_students[3];
	int		id_of_students[3];

	// Đoạn mã đọc thông tin trường đại học.
	fs.open("IntroUniversity.txt");
	if (!fs)
		return -1;
	fs 	>> name_of_university;
	cout 	<< name_of_university << endl;	// In ra thông tin tên trường.
	fs.close();

	// Đoạn mã đọc thông tin sinh viên.
	fs.open("StorageStudentInfo.txt");
	if (!fs)
		return -1;

	int index = 0;
	while (fs){
		fs 	>> name_of_students[index]	// Đọc thông tin sinh viên từ file.
			>> id_of_students[index];
		index++;
	}
	fs.close();

	PrintStudentInfo(name_of_students, id_of_students, 3);

	return 0;
}

Ghi dữ liệu

#include <fstream>
using namespace std;

int main()
{
	fstream f;
	// Ghi dữ liệu vào file
	int numberData = 1024;

	f.open("text.txt");
	f << numberData;
	f.close();
	return 0;
}

Tham khảo

THẢO LUẬN
ĐÓNG