Chào các bạn đang theo dõi khóa học lập trình trực tuyến ngôn ngữ C++.
Trong bài học này, chúng ta cùng thực hành một số thao tác ghi dữ liệu vào file thông qua file output stream mà ngôn ngữ C++ đã cung cấp.
File output
Ngôn ngữ C++ đã cung cấp cho chúng ta class ofstream để tạo lập kết nối đến file và đưa dữ liệu từ chương trình ra file, class ofstream cũng được định nghĩa bên trong thư viện fstream nên chúng ta cần include thư viện fstream vào file chương trình trước khi sử dụng:
#include <fstream>
Khác với thao tác đọc dữ liệu từ file, chúng ta có thể tạo ngay một đối tượng từ class ofstream mà không cần phải tạo sẵn một file mẫu, vì file cần mở sẽ được tạo mới khi trong thư mục mà đường dẫn trỏ đến không tồn tại.
Mình tạo một chương trình có cấu trúc như sau để làm ví dụ mẫu trong bài học này:
#include <iostream>
#include <string>
#include <fstream>
void writeDataToFile(std::string file)
{
}
void readDataFromFile(std::string file)
{
}
int main()
{
std::string filePath = "C:/Users/ADMIN/Desktop/my_document.txt";
writeDataToFile(filePath);
readDataFromFile(filePath);
return 0;
}
Ở trong hàm readDataFromFile, mình thực hiện đọc toàn bộ nội dung file và in ra màn hình để xem kết quả của quá trình ghi dữ liệu ra file như sau:
void readDataFromFile(std::string file)
{
std::ifstream fileInput(file);
if (fileInput.fail())
{
std::cout << "Cannot open file at " << file << std::endl;
return;
}
while (!fileInput.eof())
{
char line[255];
fileInput.getline(line, 255);
std::cout << line << std::endl;
}
}
Bây giờ chúng ta chỉ còn quan tâm đến hàm writeDataToFile.
Thực ra thao tác ghi dữ liệu vào file đơn giản hơn việc đọc dữ liệu từ file rất nhiều. Khi đọc dữ liệu từ file vào chương trình, chúng ta cần phải quan tâm dữ liệu trong file được tổ chức như thế nào, với định dạng như thế thì nên chọn kiểu dữ liệu nào để đọc vào cho phù hợp… rất nhiều thứ phải quan tâm. Đối với thao tác ghi dữ liệu vào file, tất cả dữ liệu sau khi ghi vào file đều trở thành kí tự văn bản, và file output stream trong C++ đã overload insertion operator (<<) cho tất cả các kiểu dữ liệu cơ bản trong C++, do đó chúng ta có thể lưu ngay các giá trị số nguyên, số thực, kí tự hoặc std::string … xuống file ngay lập tức thông qua insertion operator (<<).
void writeDataToFile(std::string file)
{
std::ofstream fileOutput(file);
if (fileOutput.fail())
{
std::cout << "Cannot open file at " << file << std::endl;
return;
}
fileOutput << "Hello world!" << std::endl;
}
Đây chính xác là một chương trình Hello world mà các bạn đã từng học. Điều khác biệt là thay vì dữ liệu ghi vào stdout và đưa ra màn hình, dòng “Hello world!” đã được ghi vào file my_document.txt
, các bạn có thể mở file my_document.txt
bằng notepad để xem nội dung được ghi vào file.
Chúng ta có thể ghi bao nhiêu dòng dữ liệu tùy ý, phụ thuộc vào dung lượng của thiết bị lưu trữ mà các bạn đang sử dụng.
void writeDataToFile(std::string file)
{
std::ofstream fileOutput(file);
if (fileOutput.fail())
{
std::cout << "Cannot open file at " << file << std::endl;
return;
}
fileOutput << "Hello world!" << std::endl;
fileOutput << "I'm Le Tran Dat" << std::endl;
fileOutput << "I worked at Singapore over 5 years" << std::endl;
for (int i = 1; i <= 10; i++)
{
fileOutput << i << std::endl;
}
}
Cách sử dụng hoàn toàn tương tự như khi các bạn sử dụng đối tượng std::cout. Tuy nhiên, đối với một số struct hoặc class tự định nghĩa, để sử dụng insertion operator (<<) cho việc ghi thông tin các trường dữ liệu vào file, chúng ta cần định nghĩa lại toán tử (<<) bên trong struct hay class đó, chúng ta sẽ cùng tìm hiểu vấn đề này trong các bài học sau.
File output modes
Với thao tác mở file để ghi dữ liệu, chúng ta cũng có một số mode khác nhau sử dụng cho từng trường hợp cụ thể.
Mode std::ios::out được sử dụng mặc định nếu các bạn khởi tạo cho đối tượng có kiểu std::ofstream, nếu các bạn sử dụng kiểu fstream (input/output stream) thì cần cung cấp thêm thông tin để compiler biết là các bạn mở file với mục đích gì:
std::fstream file("C:/Users/ADMIN/Desktop/my_document.txt", std::ios::out);
Nếu các bạn muốn ghi dữ liệu vào file dưới dạng mã hóa nhị phân, các bạn có thể thêm vào mode std::ios::binary như sau:
std::fstream file("C:/Users/ADMIN/Desktop/my_document.txt", std::ios::out | std::ios::binary);
Nếu các bạn mở file dưới mode std::ios::app, dữ liệu trong file sẽ được giữ nguyên và internal file position indicator sẽ chuyển về cuối file để ghi nối dữ liệu vào file. Các bạn có thể tự thử nghiệm với các mode trong bảng trên để thấy sự khác biệt.
Sử dụng một output stream cho nhiều file
Sau khi sử dụng phương thức close để đóng stream lại, chúng ta có thể mở một liên kết mới đến một đường dẫn khác để tiếp tục ghi dữ liệu bằng phương thức open. Ví dụ:
void writeDataToFile(std::string file)
{
std::ofstream fileOutput(file);
if (fileOutput.fail())
{
std::cout << "Cannot open file at " << file << std::endl;
return;
}
fileOutput << "Hello world!" << std::endl;
fileOutput << "I'm Le Tran Dat" << std::endl;
fileOutput << "I worked at Singapore over 5 years" << std::endl;
fileOutput.close();
fileOutput.open(file, std::ios::app);
fileOutput << "Goodbye everyone!" << std::endl;
}
Phương thức open hoạt động tương tự constructor của class ofstream, nên chúng ta có thể tạo nhiều kết nối đến nhiều file khác nhau. Tuy nhiên, chúng ta chỉ có thể kết nối đến một file duy nhất tại một thời điểm.
Hẹn gặp lại các bạn trong bài học tiếp theo trong khóa học lập trình C++ hướng thực hành.
Mọi ý kiến đóng góp hoặc thắc mắc có thể đặt câu hỏi trực tiếp tại diễn đàn.