Dmitro
Dmitro

Reputation: 1960

How can I get the file size in directory traversal?

How can I get the size of a file when I am using recursion to look at each file? I'm getting the next error:

project.exe exited with code -1073741819

int dir_size(const QString _wantedDirPath)
{
    long int sizex = 0;
    QFileInfo str_info(_wantedDirPath);
    if (str_info.isDir())
    {
        QDir dir(_wantedDirPath);
        QStringList ext_list;
        dir.setFilter(QDir::Files | QDir::Dirs |  QDir::Hidden | QDir::NoSymLinks);
        QFileInfoList list = dir.entryInfoList();

        for(int i = 0; i < list.size(); ++i)
        {
            QFileInfo fileInfo = list.at(i);
            if ((fileInfo.fileName() != ".") && (fileInfo.fileName() != ".."))
            {
                sizex += (fileInfo.isDir()) ? this->dir_size(fileInfo.path()) : fileInfo.size():
                QApplication::processEvents();
            }
        } 
    } 

    return sizex;
}

Upvotes: 7

Views: 5404

Answers (4)

BuvinJ
BuvinJ

Reputation: 11048

Here's a more developed answer for getting a directory's size. Its results match those of the utility "du" (Disk Usage).

This takes into account that Linux considers the directory entry itself to have size. It handles symlink/shortcuts correctly in both Linux and Windows (rather than ignoring them!). This also allows the ui "breathe" in a more logical manner than assuming a new directory traversal is the point at which to "rest" for a moment.

#ifdef Q_OS_WIN32
#include <sys/stat.h>
long getStdFileSize( const std::string &filename )
{
    struct stat stat_buf;
    int rc = stat( filename.c_str(), &stat_buf );
    return rc == 0 ? stat_buf.st_size : -1;
}
#endif

// designed to match the results of the standard
// cross platform utility "du" (Disk Usage)
// compare to du -b [path]
quint64 diskUsage( const QString &absPath, int &itemCount )
{
    static const int UI_REFRESH_FREQ_ITEMS_TRAVERSED( 100 );
    QFileInfo parentInfo( absPath );
    if( parentInfo.exists() ) itemCount++;    
    quint64 totalBytes =
        parentInfo.isSymLink() ?
// handle symlink size correctly
#ifdef Q_OS_WIN32
        getStdFileSize( absPath.toStdString() )
#else
        parentInfo.symLinkTarget().length()
#endif
        : parentInfo.size();
    if( parentInfo.isDir() )
    {
        QFileInfoList childInfoList = QDir( absPath ).entryInfoList(
            QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoDotAndDotDot );
        foreach( const QFileInfo &childInfo, childInfoList )
        {
            totalBytes += diskUsage(
                childInfo.absoluteFilePath(), itemCount );
            // prevent ui lockup, as this can potentially take a long time
            if( (itemCount % UI_REFRESH_FREQ_ITEMS_TRAVERSED)==0 )
                QGuiApplication::processEvents();
        }
    }
    return totalBytes;
}

// convenience overload
quint64 diskUsage( const QString &absPath )
{
    int itemCount=0;
    return diskUsage( absPath, itemCount );
}

Upvotes: 0

cor3ntin
cor3ntin

Reputation: 916

Start by cleaning your code a bit.

quint64 dir_size(const QString & str)
{
    quint64 sizex = 0;
    QFileInfo str_info(str);
    if (str_info.isDir())
    {
        QDir dir(str);
        QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs |  QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);
        for (int i = 0; i < list.size(); ++i)
        {
            QFileInfo fileInfo = list.at(i);
            if(fileInfo.isDir())
            {
                    sizex += dir_size(fileInfo.absoluteFilePath());
            }
            else 
                sizex += fileInfo.size();

        }
    }
    return sizex;
} 

If you want to keep the ui reactive, do the calcul in a separate thread, call processEvent() at each file is a burden. You should also use quint64 ( unsigned long long ) to handle big files ( > 2Go ) But, it's not clear where the crash is.

Upvotes: 8

Chenna V
Chenna V

Reputation: 10473

Its crashing because you are recursively evaluating the same folder again and again. The statement sizex += this->dir_size(fileInfo.path()); calls the same function recursively with the same folder name. So your stack keeps growing and eventually out of memory.

fileInfo.path() gives the same (parent) folder.

fileInfo.filePath() gives the filename with the path

Change it to sizex += this->dir_size(fileInfo.filePath()); and that should fix it

Upvotes: 1

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361254

Change this:

if(fileInfo.isDir())
{
     sizex += this->get_dir_size(fileInfo.path());
     QApplication::processEvents();
}

to

if(fileInfo.isDir())
{
     sizex += dir_size(fileInfo.path()); //call recursively!
     QApplication::processEvents();
}

Why do you call get_dir_size() - whatever it is? You should call dir_size() if you want to compute the size recursively.

Upvotes: 1

Related Questions