QFileInfo size() is returning shortcut TARGET size

1.3k views Asked by At

I am scanning folder size like this:

qint64 dirSize = 0;
int fileCount = 0;

for(QDirIterator itDir(someDir, QDir::NoDotAndDotDot|QDir::Files|QDir::Hidden|QDir::System,
                       QDirIterator::Subdirectories);
    itDir.hasNext(); )
{
    itDir.next();
    dirSize += itDir.fileInfo().size();
    ++fileCount;
}

This appears to work fine.

However, I noticed that a folder containing Windows shortcuts (.lnk) is returning a much larger size than expected. The reason is that the sizes of the shortcut targets are being returned, rather than the sizes of the shortcut files themselves.

But according to QFileInfo documentation:

On Windows, symlinks (shortcuts) are .lnk files. The reported size() is that of the symlink (not the link's target) [...]

So my question is: what am I doing wrong here? How do I get the size of the shortcut file?

2

There are 2 answers

0
bur On BEST ANSWER

@Rob's answer works in most cases, but returns 0 when the the shortcut's target doesn't exist/is invalid.
Taking a cue from that approach, you can also copy the shortcut and change the extension.

So combining it all into a function (I'm assuming here that opening the target is cheaper/safer than copying the shortcut):

qint64 getFileSize(const QString &path)
{
    qint64 size = 0;
    QFileInfo fileInfo(path);

    if(fileInfo.isSymLink() && fileInfo.size() == QFileInfo(fileInfo.symLinkTarget()).size())
    {
        // Try this approach first
        QFile file(path);
        if(file.exists() && file.open(QIODevice::ReadOnly))
            size = file.size();
        file.close();

        // If that didn't work, try this
        if(size == 0)
        {
            QString tmpPath = path+".tmp";
            for(int i=2; QFileInfo().exists(tmpPath); ++i) // Make sure filename is unique
                tmpPath = path+".tmp"+QString::number(i);

            if(QFile::copy(path, tmpPath))
            {
                size = QFileInfo(tmpPath).size();
                QFile::remove(tmpPath);
            }
        }
    }
    else size = fileInfo.size();

    return size;
}
3
Rob On

For testing purposes I created a shortcut of one of the Qt's DLL files. I placed this shortcut into an empty folder. I also created a shortcut of Qt's sdktool.exe and placed this into the same folder.

I also noticed that the size() returns the size of the actual file and not the size of shortcut. I remember I had somewhat similiar behaviour in my old project and what I did was that I opened the file before reading the size.

for (QDirIterator itr(someDir, QDir::NoDotAndDotDot|QDir::Files|QDir::Hidden|QDir::System,
                      QDirIterator::Subdirectories); itr.hasNext();) {
    itr.next();

    // Shows wrong size
    qDebug() << itr.fileName() << ", size (unopened): " << itr.fileInfo().size();

    QFile file(itr.filePath());
    if (file.exists() && file.open(QIODevice::ReadOnly)) {
        // Now the size shows correctly
        qDebug() << "Size when opened: " << file.size();
        file.close();
    }
}

Outputs:

"sdktool.lnk" , size (unopened):  2817024
Size when opened:  1325
"test.lnk" , size (unopened):  4429312
Size when opened:  951

Windows 10's File Property window shows that the size of "test.lnk" is 951 bytes and the size of "sdktool.lnk" is 1325 bytes.