Trong phần này chúng ta sẽ học về cách làm việc với file và thư mục.
QFile
, QDir
, và QFileInfo
là các lớp chuyên làm việc với file trong Qt5. QFile
cho phép bạn đọc và ghi file, QDir
cho phép bạn truy cập và xem nội dung thư mục. QFileInfo
cung cấp các thông tin về file độc lập với hệ thống, bao gồm tên file, đường dẫn thư mục, thời gian chỉnh sửa lần cuối, quyền đọc ghi hay quyền sở hữu.
Kích thước file
Ví dụ dưới đây lấy kích thước của một file
#include <QTextStream> #include <QFileInfo> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { qWarning("Usage: file_size file"); return 1; } QString filename = argv[1]; if (!QFile(filename).exists()) { qWarning("The file does not exist"); return 1; } QFileInfo fileinfo(filename); qint64 size = fileinfo.size(); QString str = "The size is: %1 bytes"; out << str.arg(size) << endl; }
Kích thước file có thể truy xuất thông qua phương thức size()
.
QString filename = argv[1];
Chúng ta lấy tên file qua tham số truyền vào chương trình.
if (!QFile(filename).exists()) { qWarning("The file does not exist"); return 1; }
Kiểm tra xem file đã tồn tại hay chưa bằng phương thức exists(),
nếu chưa tồn tại thì cho in thông báo và thoát chương trình.
QString str = "The size is: %1 bytes"; out << str.arg(size) << endl;
In kết quả ra màn hình.
The size is: 28029 bytes
Đọc file trong Qt
Muốn đọc file thì trước tiên phải mở file đó ra đã. Các phương thức mở file sẽ trả về một stream để đọc file, nếu đã từng lập trình với Java hay C# thì có lẽ bạn đã từng được học về khái niệm stream, còn nếu chưa thì bạn cứ hiểu stream giống như std::cin
hay std::cout
trong thư viện <iostream>
của C++ ấy, chỉ khác là trong C++ thường thì cin
và cout
mặc định làm việc với màn hình và bàn phím, còn trong Qt thì làm việc với file.
#include <QTextStream> #include <QFile> int main(void) { QTextStream out(stdout); QFile file("colours"); if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading"); return 1; } QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); out << line << endl; } file.close(); }
Ví dụ trên đọc dữ liệu từ file colours
. Trong đó chứa tám string.
if (!file.open(QIODevice::ReadOnly)) { qWarning("Cannot open file for reading"); return 1; }
Phương thức open()
sẽ mở file ở chế độc read-only. Nếu giá trị trả về false thì ta báo không mở file được và cho thoát chương trình.
QTextStream in(&file);
Tạo một đối tượng thuộc lớp QTextStream
nhận vào đối tượng QFile.
Đây chính là một stream và ta sẽ dùng nó để đọc file.
while (!in.atEnd()) { QString line = in.readLine(); out << line << endl; }
Trong vòng lặp while, chúng ta sẽ đọc file theo từng dòng cho đến hết file bằng phương thức readLine()
, mỗi dòng trong file sẽ được lưu vô một biến QString
rồi in ra màn hình. Phương thức atEnd()
kiểm tra xem đã hết file hay chưa.
file.close();
Khi đã đọc file xong ta dùng phương thức close()
để đóng file.
red green blue yellow brown white black violet
Ghi file trong Qt
Để ghi file thì cũng tương tự như đọc file, phải mở được file đó trước. Và cũng như đọc file, chúng ta sẽ có một stream riêng để ghi file.
#include <QTextStream> #include <QFile> int main(void) { QTextStream out(stdout); QString filename = "distros"; QFile file(filename); if (file.open(QIODevice::WriteOnly)) { QTextStream out(&file); out << "Xubuntu" << endl; out << "Arch" << endl; out << "Debian" << endl; out << "Redhat" << endl; out << "Slackware" << endl; } else { qWarning("Could not open file"); } file.close(); }
Ví dụ trên ghi tên 5 phiên bản của hệ điều hành họ Linux vào một file tên là distros
.
QString filename = "distros"; QFile file(filename);
Tạo một đối tượng QFile
với tên file.
if (file.open(QIODevice::WriteOnly))
Mở file ở chế độ WriteOnly
với phương thức open()
.
QTextStream out(&file);
Dòng code trên tạo ra một đối tượng QTextStream
để ghi file.
out << "Xubuntu" << endl; out << "Arch" << endl; out << "Debian" << endl; out << "Redhat" << endl; out << "Slackware" << endl;
Dùng toán tử << để ghi dữ liệu.
file.close();
Cuối cùng đóng file lại.
Xubuntu Arch Debian Redhat Slackware
Copy một file trong Qt
Xem ví dụ để biết cách copy file.
#include <QTextStream> #include <QFile> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 3) { qWarning("Usage: copyfile source destination"); return 1; } QString source = argv[1]; if (!QFile(source).exists()) { qWarning("The source file does not exist"); return 1; } QString destin(argv[2]); QFile::copy(source, destin); }
Qt cung cấp phương thức QFile::copy()
để copy một file, tham số gồm file gốc và file đích sẽ được tạo ra.
if (argc != 3) { qWarning("Usage: copyfile source destination"); return 1; }
Ở đây mình truyền vào chương trình 2 tham số là tên file gốc và tên file đích. Nếu không đủ cả 2 thì ta báo lỗi và thoát chương trình.
QString source = argv[1];
Lấy tên file gốc từ tham số đầu tiên.
if (!QFile(source).exists()) { qWarning("The source file does not exist"); return 1; }
Kiểm tra xem file gốc có tồn tại hay không, nếu không thì in ra thông báo lỗi và thoát chương trình.
QString destin(argv[2]);
Lấy file đích.
QFile::copy(source, destin);
Dùng phương thức QFile::copy()
để copy file gốc sang file đích.
Làm việc với thư mục trong Qt
Lớp QDir
được sinh ra để làm việc này. Xem ví dụ.
#include <QTextStream> #include <QDir> int main(void) { QTextStream out(stdout); QDir dir; if (dir.mkdir("mydir")) { out << "mydir successfully created" << endl; } dir.mkdir("mydir2"); if (dir.exists("mydir2")) { dir.rename("mydir2", "newdir"); } dir.mkpath("temp/newdir"); }
Ở trên mình trình bày bốn phương thức thường dùng của lớp này.
if (dir.mkdir("mydir")) { out << "mydir successfully created" << endl; }
Phương thức mkdir()
tạo ra một thư mục. Trả về true nếu tạo thành công.
if (dir.exists("mydir2")) { dir.rename("mydir2", "newdir"); }
Phương thức exists()
kiểm tra xem một thư mục đã tồn tại hay chưa. Phương thức rename()
đổi tên một thư mục.
dir.mkpath("temp/newdir");
Phương thức mkpath()
tạo ra một thư mục và tạo cả các thư mục cha của nó nếu chưa có.
Một số hằng số về các thư mục đặc biệt
Trong hệ thống có một số thư mục đặc biệt, chẳng hạn như thư mục home hay thư mục gốc. Xem ví dụ.
#include <QTextStream> #include <QDir> int main(void) { QTextStream out(stdout); out << "Current path:" << QDir::currentPath() << endl; out << "Home path:" << QDir::homePath() << endl; out << "Temporary path:" << QDir::tempPath() << endl; out << "Rooth path:" << QDir::rootPath() << endl; }
Ví dụ trên in ra bốn thư mục đặc biệt
out << "Current path:" << QDir::currentPath() << endl;
Phương thức QDir::currentPath()
trả về thư mục mà mình đang làm việc chẳng hạn ở trên mình đang làm việc với file special_paths.cpp thì phương thức này sẽ in ra đường dẫn đến file này.
out << "Home path:" << QDir::homePath() << endl;
Phương thức QDir::homePath()
trả về đường dẫn đến thư mục user của bạn.
out << "Temporary path:" << QDir::tempPath() << endl;
Phương thức QDir::tempPath()
trả về đường dẫn đến thư mục temp của user của bạn.
out << "Rooth path:" << QDir::rootPath() << endl;
Phương thức QDir::rootPath()
trả về đường dẫn đến thư mục gốc của bạn, nếu bạn dùng Windows thì thường nó là thư mục cài win, nếu dùng linux thì là dấu /.
Đường dẫn file
Xem ví dụ.
#include <QTextStream> #include <QFileInfo> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { out << "Usage: file_times file" << endl; return 1; } QString filename = argv[1]; QFileInfo fileinfo(filename); QString absPath = fileinfo.absoluteFilePath(); QString baseName = fileinfo.baseName(); QString compBaseName = fileinfo.completeBaseName(); QString fileName = fileinfo.fileName(); QString suffix = fileinfo.suffix(); QString compSuffix = fileinfo.completeSuffix(); out << "Absolute file path: " << absPath << endl; out << "Base name: " << baseName << endl; out << "Complete base name: " << compBaseName << endl; out << "File name: " << fileName << endl; out << "Suffix: " << suffix << endl; out << "Whole suffix: " << compSuffix << endl; }
Trong ví dụ trên ta in ra đường dẫn của một file và trính xuất một vài thành phần trong đường dẫn đó.
QFileInfo fileinfo(filename);
Dùng lớp QFileInfo
để làm việc này.
QString absPath = fileinfo.absoluteFilePath();
Phương thức absoluteFilePath()
trả về đường dẫn đầy đủ của file.
QString baseName = fileinfo.baseName();
Phương thức baseName()
trả về tên file, không lấy phần mở rộng của file, không lấy đường dẫn thư mục.
QString compBaseName = fileinfo.completeBaseName();
Phương thức completeBaseName()
cũng giống với phương thức baseName().
QString fileName = fileinfo.fileName();
Phương thức fileName()
trả về tên file và cả phần mở rộng của file.
QString suffix = fileinfo.suffix();
Phương thức suffix()
trả về phần mở rộng của file.
QString compSuffix = fileinfo.completeSuffix();
Phương thức completeSuffix()
cũng giống với phương thức suffix().
Liệt kê nội dung thư mục trong Qt
Ví dụ dưới đây liệt kê nội dung của một thư mục.
#include <QTextStream> #include <QFileInfo> #include <QDir> int main(int argc, char *argv[]) { QTextStream out(stdout); if (argc != 2) { qWarning("Usage: list_dir directory"); return 1; } QString directory = argv[1]; QDir dir(directory); if (!dir.exists()) { qWarning("The directory does not exist"); return 1; } dir.setFilter(QDir::Files | QDir::AllDirs); dir.setSorting(QDir::Size | QDir::Reversed); QFileInfoList list = dir.entryInfoList(); int max_size = 0; foreach (QFileInfo finfo, list) { QString name = finfo.fileName(); int size = name.size(); if (size > max_size) { max_size = size; } } int len = max_size + 2; out << QString("Filename").leftJustified(len).append("Bytes") << endl; for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); QString str = fileInfo.fileName().leftJustified(len); str.append(QString("%1").arg(fileInfo.size())); out << str << endl; } return 0; }
Dùng phương thức entryInfoList()
trong lớp QDir
để làm việc này. Trong code ví dụ trên chúng ta in ra danh sách đã được sắp xếp theo kích thước của file/thư mục. Chúng ta in ra hai cột, cột đầu tiên là tên file/thư mục, cột thứ hai là kích thước file/thư mục.
QDir dir(directory);
Tạo ra một đối tượng QDir
.
dir.setFilter(QDir::Files | QDir::AllDirs);
Phương thức setFilter()
có tác dụng lọc các thành phần mà mình muốn liệt kê, trong ví dụ mình lọc ra cả file và thư mục.
dir.setSorting(QDir::Size | QDir::Reversed);
Phương thức setSorting()
sẽ tự động sắp xếp các thành phần trong thư mục dựa theo tham số truyền vào mà ở đây là sắp xếp đảo ngược theo kích thước.
QFileInfoList list = dir.entryInfoList();
Phương thức entryInfoList()
sẽ trả về một đối tượng thuộc lớp QFileInfoList,
lớp này là một danh sách các đối tượng QFileInfo
đã được sắp xếp. Lớp này tương tự với QList<QFileInfo>
.
foreach (QFileInfo finfo, list) { QString name = finfo.fileName(); int size = name.size(); if (size > max_size) { max_size = size; } }
Duyệt qua danh sách và tìm ra file có độ dài lớn nhất. Mình lấy thông tin này ra để lát sau in kết quả ra màn hình thì có thể ngăn cách hai cột cho đẹp.
int len = max_size + 2;
Chúng ta cũng không dùng chính xác độ dài lớn nhất mà cộng thêm 2 vào nữa.
for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); QString str = fileInfo.fileName().leftJustified(len); str.append(QString("%1").arg(fileInfo.size())); out << str << endl; }
Cuối cùng ta duyệt qua toàn bộ danh sách và in kết quả ra màn hình.
Filename Bytes list_dir.pro 291 list_dir.cpp 1092 .. 4096 . 4096 list_dir.o 10440 list_dir 19075 Makefile 28369
Trong bài này, bạn đã được học cách làm việc với file và thư mục trong Qt.