As a Qt developer, Qt provides me with a lot of useful infrastructure, such as the popular QString, QNetwork, etc. This is what the Qt platform provides me with, and I only need to develop on this platform.

As a C++ developer, the C++ standard library is also the infrastructure I need to use, but the standard library provides less functionality than Qt, most notably the C++ std::string, which has been the subject of much disdain and abuse in the industry.

But this situation will be improved after the C++ 20 standard, so I won’t go into details here, but in the future I’ll prepare to write an introduction to the features of C++ 20.

Today, when I was developing my project, I only used the standard library to save resources, and the lack of Qt platform provided me with favorable help, the project development difficulty increased instantly.

QDir

The basic idea of Qt is that inheritance is greater than combination, so Qt provides us with a variety of inherited classes, and in Qt we use the QDir class for directory operations.

The QDir class uses relative or absolute file paths to point to a file or directory. If you always use “/” as a directory separator, Qt will translate your path to match the underlying operating system.

The QDir class does not inherit from QObject or other QIO classes because it does not involve IO specific operations.

QDir provides a very large number of methods to easily get the name of a directory, absolute paths, relative paths, set directory filters, etc.

A basic usage is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
QDir dir("/tmp");
if (!dir.exists()) {
    return
}

for (const QFileInfo& item : dir.entryInfoList()) {
    if (item.isDir()) {
        // ...
      }
}

dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
dir.setSorting(QDir::Size | QDir::Reversed);

const QFileInfoList& list = dir.entryInfoList();
for (const QFileInfo& item : list) {
    // ...
}

As you can see in the sample code above, QDir as a whole is very object-oriented. We use QDir objects to perform various operations on directories, and when it comes to specific files (directories are special files), we can use the QFileInfo class to get information about the specific files.

In addition to the methods mentioned in the above demo, QDir has many other methods, including the count() method to count the number of files and directories in a directory, and the remove() method to delete a specified directory, so we won’t list them all here.

QDir supports a variety of filter settings. Both Filtering and Sorting affect the content returned by the entryInfoList method.

QDir accepts an enumeration of filters:

enum enum value description
QDir::Dirs 0x001 Lists the directories that match the filter.
QDir::AllDirs 0x400 List all directories; i.e., do not apply the filter to directory names.
QDir::Files 0x002 List the documents.
QDir::Drives 0x004 List disk drives (ignored under Unix).
QDir::NoSymLinks 0x008 Do not list symbolic links (ignored by operating systems that do not support symbolic links).
QDir::NoDotAndDotDot NoDot NoDotDot
QDir::NoDot 0x2000 Do not list special entries “.”.
QDir::NoDotDot 0x4000 Do not list special entries “..” .
QDir::AllEntries Dirs Files
QDir::Readable 0x010 Lists the files to which the application has read access. Readable values need to be merged with Dirs or Files.
QDir::Writable 0x020 Lists the files to which the application has write access. The writable value needs to be merged with Dirs or Files.
QDir::Executable 0x040 Lists the files to which the application has execute access. Executable values need to be merged with Dirs or Files.
QDir::Modified 0x080 List only the files that have been modified (ignored on Unix).
QDir::Hidden 0x100 List hidden files (on Unix, files starting with “.” files starting with “.”).
QDir::System 0x200 List system files (including Unix, FIFO, socket and device files; on Windows, including .lnk files)
QDir::CaseSensitive 0x800 Filters should be case-sensitive.

QDir accepted sorting enumeration:

enum enum value description
QDir::Name 0x00 Sort by name.
QDir::Time 0x01 Sort by time (modification time).
QDir::Size 0x02 Sort by file size.
QDir::Type 0x80 Sort by file type (extension).
QDir::Unsorted 0x03 Do not sort.
QDir::NoSort -1 Unsorted by default.
QDir::DirsFirst 0x04 Put the directory first, then the files.
QDir::DirsLast 0x20 Put the file first, then the directory.
QDir::Reversed 0x08 Reverses the sort order.
QDir::IgnoreCase 0x10 Case-insensitive sorting.
QDir::LocaleAware 0x40 Use the current region settings to sort items appropriately.

std::filesystem

The above describes the design style of Qt, while the design style of the standard library is one of combination over inheritance. The standard library provides a variety of very specific classes or functions that break down a series of operations into their individual subparts to complete the task.

Here’s a small example to illustrate:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
std::filesystem::path tmp{"/tmp"};
if (!std::filesystem::exists(tmp)) {
    std::cout << "目录不存在" << std::endl;
    return;
}

const bool result = std::filesystem::create_directories(tmp);
if (!result) {
    std::cout << "目录创建失败,也许是已经存在。" << std::endl;
}

for (auto const& dir_entry : std::filesystem::directory_iterator(tmp)) {
    if (dir_entry.is_directory()) {
        // ...
    }
}

if (std::filesystem::is_directory(tmp)) {
    // ...
}

As you can see, the C++ standard library uses multiple classes together to inspect and traverse the directory. This combination-based approach allows for more flexibility, and if a part needs to be modified, it can be done by simply inheriting the specific class, which is not so easy with Qt’s QDir.

When using the standard library it is important to note that the standard library does not usually constrain the user, using the current example as an example, QDir provides filter enumeration to help developers simply implement file filtering, but std::filesystem does not provide such an interface, the standard library provides the mechanism, but not the policy, developers need to use the various interface, combination out of their own business, so if you want to use the standard library can also achieve filtering and sorting, you can only provide their own corresponding operations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
std::filesystem::path tmp{ "/tmp" };
std::vector<std::filesystem::directory_entry> list;
std::vector<std::string> filter{ ".jpg", ".txt" };
std::filesystem::directory_iterator iter{ tmp };
std::copy_if(iter.begin(),
             iter.end(),
             std::back_inserter(list),
             [filter](std::filesystem::directory_entry entry) {
                return !entry.is_directory() && 
                       std::find_if(filter.begin(),
                                    filter.end(),
                                    [entry](std::string s) {
                                      return entry.path().extension() == s;
                                    }
                       );
              }
);

As you can see, the code has become incredibly ugly

The standard library provides some convenient functions such as std::copy_if, std::back_inserter, and std::find_if, as well as the more commonly used std::transform. The standard library provides an iterator abstraction so that we can use iterator objects and iterator algorithms to easily perform various traversals, copies, and transformations. copying and conversions using iterator objects and iterator algorithms.

As you can see from the above examples, Qt does provide developers with a good deal of help, which is within the capabilities of Qt as a platform, but of course, even if we use Qt, we can still write the same code as above.

Summary

Qt has recently been trying to use the contents of the standard library to replace some of its own components, and the latest Qt6 has been upgraded to the C++ 17 standard, changing the qSort macro to use std::sort, so maybe in the near future we won’t have to argue or take sides over whether to use Qt or the standard library.