15

中是否有任何 API用于获取指定文件夹的大小?

如果没有,我怎样才能得到一个文件夹的总大小,包括所有子文件夹和文件?

4

13 回答 13

10

让操作系统为你做这件事怎么样:

long long int getFolderSize(string path) 
{
    // command to be executed
    std::string cmd("du -sb ");
    cmd.append(path);
    cmd.append(" | cut -f1 2>&1");

    // execute above command and get the output
    FILE *stream = popen(cmd.c_str(), "r");
    if (stream) {
        const int max_size = 256;
        char readbuf[max_size];
        if (fgets(readbuf, max_size, stream) != NULL) {
            return atoll(readbuf);
        }   
        pclose(stream);            
    }           
    // return error val
    return -1;
}
于 2013-03-19T11:14:30.210 回答
9

其实我不想使用任何第三方库。只想用纯c++实现。

如果您使用 MSVC++,您将拥有<filesystem>“作为标准 C++”。 但是使用 boost 或 MSVC - 两者都是“纯 C++”。

如果您不想使用 boost,而只有 C++ std:: library 这个答案有点接近。正如您在此处看到的,有一个 Filesystem Library Proposal (Revision 4)。在这里你可以阅读:

该库的 Boost 版本已经广泛使用了十年。该库的 Dinkumware 版本基于 N1975(相当于 Boost 库的第 2 版),随 Microsoft Visual C++ 2012 一起提供。

为了说明使用,我改编了@Nayana Adassuriya的答案,做了非常小的修改(好吧,他忘了初始化一个变量,我使用了unsigned long long,最重要的是使用:path filePath(complete (dirIte->path(), folderPath));在调用其他函数之前恢复完整路径)。我已经测试过,它在 Windows 7 中运行良好。

#include <iostream>
#include <string>
#include <filesystem>
using namespace std;
using namespace std::tr2::sys;

void  getFoldersize(string rootFolder,unsigned long long & f_size)
{
   path folderPath(rootFolder);                      
   if (exists(folderPath))
   {
        directory_iterator end_itr;
        for (directory_iterator dirIte(rootFolder); dirIte != end_itr; ++dirIte )
        {
            path filePath(complete (dirIte->path(), folderPath));
           try{
                  if (!is_directory(dirIte->status()) )
                  {
                      f_size = f_size + file_size(filePath);                      
                  }else
                  {
                      getFoldersize(filePath,f_size);
                  }
              }catch(exception& e){  cout << e.what() << endl; }
         }
      }
    }

int main()
{
    unsigned long long  f_size=0;
    getFoldersize("C:\\Silvio",f_size);
    cout << f_size << endl;
    system("pause");
    return 0;
}
于 2013-03-19T14:06:07.833 回答
5

您可以通过这种方式使用 boost。您可以尝试更深入地优化它。

#include <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string.hpp>



    using namespace std;
    namespace bsfs = boost::filesystem; 

    void  getFoldersize(string rootFolder,long & file_size){
        boost::replace_all(rootFolder, "\\\\", "\\");   
        bsfs::path folderPath(rootFolder);                      
        if (bsfs::exists(folderPath)){
            bsfs::directory_iterator end_itr;

            for (bsfs::directory_iterator dirIte(rootFolder); dirIte != end_itr; ++dirIte )
            {
                bsfs::path filePath(dirIte->path());
                try{
                    if (!bsfs::is_directory(dirIte->status()) )
                    {

                        file_size = file_size + bsfs::file_size(filePath);                      
                    }else{
                        getFoldersize(filePath.string(),file_size);
                    }
                }catch(exception& e){               
                    cout << e.what() << endl;
                }
            }
        }

    }

    int main(){
        long file_size =0;
        getFoldersize("C:\\logs",file_size);
        cout << file_size << endl;
        system("pause");
        return 0;
    }
于 2013-03-19T10:36:43.303 回答
4

文件夹中文件的大小 请查看此链接

#include <iostream>
#include <windows.h>
#include <string>
using namespace std;


__int64 TransverseDirectory(string path)
{
    WIN32_FIND_DATA data;
    __int64 size = 0;
    string fname = path + "\\*.*";
    HANDLE h = FindFirstFile(fname.c_str(),&data);
    if(h != INVALID_HANDLE_VALUE)
    {
        do {
            if( (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
            {
                // make sure we skip "." and "..".  Have to use strcmp here because
                // some file names can start with a dot, so just testing for the 
                // first dot is not suffient.
                if( strcmp(data.cFileName,".") != 0 &&strcmp(data.cFileName,"..") != 0)
                {
                    // We found a sub-directory, so get the files in it too
                    fname = path + "\\" + data.cFileName;
                    // recurrsion here!
                    size += TransverseDirectory(fname);
                }

            }
            else
            {
                LARGE_INTEGER sz;
                // All we want here is the file size.  Since file sizes can be larger
                // than 2 gig, the size is reported as two DWORD objects.  Below we
                // combine them to make one 64-bit integer.
                sz.LowPart = data.nFileSizeLow;
                sz.HighPart = data.nFileSizeHigh;
                size += sz.QuadPart;

            }
        }while( FindNextFile(h,&data) != 0);
        FindClose(h);

    }
    return size;
}

int main(int argc, char* argv[])
{
    __int64 size = 0;
    string path;
    size = TransverseDirectory("c:\\dvlp");
    cout << "\n\nDirectory Size = " << size << "\n";
    cin.ignore();
    return 0;
}

更多详情请点击这里

于 2013-03-19T09:36:00.357 回答
3

这样的事情会更好地避免添加符号(软)链接:

std::uintmax_t directorySize(const std::filesystem::path& directory)
{
    std::uintmax_t size{ 0 };
    for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
    {
        if (entry.is_regular_file() && !entry.is_symlink())
        {
            size += entry.file_size();
        }
    }
    return size;
}
于 2020-06-22T19:49:43.023 回答
1

文件系统函数是每个操作系统的组成部分,主要是用 C 和汇编程序而不是 C++ 编写的,为此的每个 C++ 库实现都以某种方式封装了这些函数。考虑一下努力,如果您不会在不同的操作系统中使用您的实现,那么直接使用这些功能并节省一些开销和时间可能是一个好主意。

最好的祝福。

于 2013-03-19T14:25:44.407 回答
1

我有我的类型定义文件:

typedef std::wstring String;
typedef std::vector<String> StringVector;
typedef unsigned long long uint64_t;

代码是:

uint64_t CalculateDirSize(const String &path, StringVector *errVect = NULL, uint64_t size = 0)
{
    WIN32_FIND_DATA data;
    HANDLE sh = NULL;
    sh = FindFirstFile((path + L"\\*").c_str(), &data);

    if (sh == INVALID_HANDLE_VALUE )
    {
        //if we want, store all happened error  
        if (errVect != NULL)
            errVect ->push_back(path);
        return size;
    }

    do
    {
        // skip current and parent
        if (!IsBrowsePath(data.cFileName))
        {
            // if found object is ...
            if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
                // directory, then search it recursievly
                size = CalculateDirSize(path + L"\\" + data.cFileName, NULL, size);
            else
                // otherwise get object size and add it to directory size
                size += (uint64_t) (data.nFileSizeHigh * (MAXDWORD ) + data.nFileSizeLow);
        }

    } while (FindNextFile(sh, &data)); // do

    FindClose(sh);

    return size;
} 

bool IsBrowsePath(const String& path)
{
    return (path == _T(".") || path == _T(".."));
}

如果需要,这使用 UNICODE 并返回失败的目录。

调用使用:

StringVector vect;
CalculateDirSize(L"C:\\boost_1_52_0", &vect);
CalculateDirSize(L"C:\\boost_1_52_0");

但永远不会通过size

于 2013-07-25T13:43:24.620 回答
1
//use FAT32   
#undef UNICODE        // to flag window deactive unicode
#include<Windows.h>  //to use windows api
#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
#pragma pack(1)  //tell compiler do'nt do prag
struct BPB
{
BYTE            JMP[3];
BYTE            OEM[8];
WORD            NumberOfBytesPerSector;
BYTE            NumberOfSectorsPerCluster;
WORD            NumberOfReservedSectors;
BYTE            NumberOfFATs;
WORD            NumberOfRootEntries16;
WORD            LowNumbferOfSectors;
BYTE            MediaDescriptor;
WORD            NumberOfSectorsPerFAT16;
WORD            NumberOfSectorsPerTrack;
WORD            NumberOfHeads;
DWORD           NumberOfHiddenSectors;
DWORD           HighNumberOfSectors;

DWORD           NumberOfSectorsPerFAT32;
WORD            Flags;
WORD            FATVersionNumber;
DWORD           RootDirectoryClusterNumber;
WORD            FSInfoSector;
WORD            BackupSector;
BYTE            Reserver[12];
BYTE            BiosDrive;
BYTE            WindowsNTFlag;
BYTE            Signature;
DWORD           VolumeSerial;
BYTE            VolumeLabel[11];
BYTE            SystemID[8];
BYTE            CODE[420];
WORD            BPBSignature;
};
//-----------------------------------------------------------
struct DirectoryEntry
{
BYTE Name[11];
BYTE Attributes;
BYTE Reserved;
BYTE CreationTimeTenth;
WORD CreationTime;
WORD CreationDate;
WORD LastAccessTime;
WORD HiClusterNumber;
WORD WriteTime;
WORD WriteDate;
WORD LowClusterNumber;
DWORD FileSize;   //acual size of file
};
//---------------------------------------------------
void dirFunction(string s){
string path = "\\\\.\\" + s + ":";
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ|GENERIC_WRITE,
    FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open partition 
BPB bootSector;//var from bootSector structure
DWORD readBytes = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
    cout << "Error " << GetLastError()<<endl;
    return;
}
ReadFile(hFile, (BYTE*)&bootSector, sizeof(bootSector), &readBytes, 0);//read partition and load bootSector information inside our structure
LONG t = 0;
ULONG distance = bootSector.NumberOfReservedSectors +
    bootSector.NumberOfFATs*bootSector.NumberOfSectorsPerFAT32;//distance from begine until Root Directory or content of partetion
distance *= bootSector.NumberOfBytesPerSector;//convert distance number to bytes value

SetFilePointer(hFile, distance, &t, FILE_BEGIN);//set pointer to root directory begine or begine of data
int clusterSize = bootSector.NumberOfBytesPerSector*bootSector.NumberOfSectorsPerCluster; //cluster size 
int NumberOfEntries = clusterSize / sizeof(DirectoryEntry); //number of record inside cluster
DirectoryEntry*  root = new DirectoryEntry[NumberOfEntries];//descripe the partetion
ReadFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
DWORD clusterNumber;
for (int i = 0; i < NumberOfEntries; i++)
{
    if (root[i].Name[0] == 0)//there no entery after this
        break;
    if (root[i].Name[0] == 0xE5)
        continue;
    if ((root[i].Attributes & 0xF) == 0xF)
        continue;
    for (int j = 0; j < 8; j++)
        cout << root[i].Name[j];
    if((root[i].Attributes & 0x10) != 0x10){
        cout<<".";
    for (int j = 8; j < 11; j++)
        cout << root[i].Name[j];
    }
    if ((root[i].Attributes & 0x10) == 0x10){
        cout << "\t<Folder>" ;
    }else{

        cout<<"\t<File>" ;
    }
    clusterNumber = root[i].HiClusterNumber << 16;
    clusterNumber |= root[i].LowClusterNumber;
    cout <<"\t"<<root[i].FileSize<<"bytes" << "\t" << clusterNumber<<"cluster" << endl;
}

CloseHandle(hFile);
}
//---------------------------------------------------------------
string convertLowerToUpper(string f){

string temp = "";
for (int i = 0; i < f.size(); i++){

    temp += toupper(f[i]);
}

return temp;
}
//---------------------------------------------------------------
string getFileName(BYTE filename[11]){
string name = "";
for (int i = 0; i < 8; i++){
    if (filename[i] != ' ')
        name += filename[i];
    }
return (name);

}
//------------------------------------------------------------------
int findEntryNumber(DirectoryEntry*  root, int NumberOfEntries, string required){
string n;
int j = 0;
for (int i = 0; i < NumberOfEntries; i++){

    if (strcmp((getFileName(root[i].Name).c_str()), convertLowerToUpper(required).c_str()) == 0){

        return i;
    }


}

return -1;
}
//---------------------------------------------------------------
void typeFunction(string fileName, string s){
string path = "\\\\.\\" + s + ":";
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ|GENERIC_WRITE,
    FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open partition 
BPB bootSector;//var from bootSector structure
DWORD readBytes = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
    cout << "Error " << GetLastError()<<endl;
    return;
}
ReadFile(hFile, (BYTE*)&bootSector, sizeof(bootSector), &readBytes, 0);//read partition and load bootSector information inside our structure
LONG t = 0;
ULONG distance = bootSector.NumberOfReservedSectors +
    bootSector.NumberOfFATs*bootSector.NumberOfSectorsPerFAT32;//distance from begine until Root Directory or content of partetion
distance *= bootSector.NumberOfBytesPerSector;//convert distance number to bytes value

SetFilePointer(hFile, distance, &t, FILE_BEGIN);//set pointer to root directory begine or begine of data
int clusterSize = bootSector.NumberOfBytesPerSector*bootSector.NumberOfSectorsPerCluster; //cluster size 
int NumberOfEntries = clusterSize / sizeof(DirectoryEntry); //number of record inside cluster
DirectoryEntry*  root = new DirectoryEntry[NumberOfEntries];//descripe the partetion
ReadFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
DWORD clusterNumber;
int index = findEntryNumber(root, NumberOfEntries, fileName);
if (index == -1){

    cout << "File is not found" << endl;
    return;
}
if (((root[index].Attributes & 0x10) == 0x10) ){

    cout << "Is not file name" << endl;
    return;
}
clusterNumber = root[index].HiClusterNumber << 16;
clusterNumber |= root[index].LowClusterNumber;
ULONG temp = (clusterNumber - 2) * clusterSize;
distance += temp;
t = 0;
SetFilePointer(hFile, distance, &t, FILE_BEGIN);
BYTE* buffer = new BYTE[clusterSize];
readBytes = 0;


    ReadFile(hFile, (BYTE*)buffer, clusterSize, &readBytes, 0);

    for (int i = 0; i < root[index].FileSize; i++){

        cout << buffer[i];
    }

    cout << endl;
    CloseHandle(hFile);

}
 //----------------------------------------------------------------------
void delFunction(string filename, string s){
string path = "\\\\.\\" + s + ":";
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ|GENERIC_WRITE,
    FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open partition 
BPB bootSector;//var from bootSector structure
DWORD readBytes = 0;
if (hFile == INVALID_HANDLE_VALUE)
{
    cout << "Error " << GetLastError()<<endl;
    return;
}
ReadFile(hFile, (BYTE*)&bootSector, sizeof(bootSector), &readBytes, 0);//read partition and load bootSector information inside our structure
LONG t = 0;
ULONG distance = bootSector.NumberOfReservedSectors +
    bootSector.NumberOfFATs*bootSector.NumberOfSectorsPerFAT32;//distance from begine until Root Directory or content of partetion
distance *= bootSector.NumberOfBytesPerSector;//convert distance number to bytes value

SetFilePointer(hFile, distance, &t, FILE_BEGIN);//set pointer to root directory begine or begine of data
int clusterSize = bootSector.NumberOfBytesPerSector*bootSector.NumberOfSectorsPerCluster; //cluster size 
int NumberOfEntries = clusterSize / sizeof(DirectoryEntry); //number of record inside cluster
DirectoryEntry*  root = new DirectoryEntry[NumberOfEntries];//descripe the partetion
ReadFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
DWORD clusterNumber;
readBytes = 0;
t = 0;
int index = findEntryNumber(root, NumberOfEntries, filename);
if (index == -1){

    cout << "FIle is not found" << endl;
    return;
}
if ((root[index].Attributes & 0x10) == 0x10){

    cout << "Is not file name" << endl;
    return;
}

//delete file
root[index].Name[0] = 0xE5;
SetFilePointer(hFile, distance, &t, FILE_BEGIN);
WriteFile(hFile, (BYTE*)root, clusterSize, &readBytes, 0);
cout<<filename<<" is deleted\n";

CloseHandle(hFile);

}
//----------------------------------------------------------------------
string removeExtention(string s){

string t = "";

for (int i = 0; i < s.size(); i++){

    if (s[i] == '.')break;
    t += s[i];
}

return t;

}
//-------------------------------------------------------------------
void main()
{
string swich_value;
string directory;
string file_name;
//dirFunction("G");
cout<<"plz, Enter single Partition character ------> example E or G\n\n";
cin>>directory;
string path = "\\\\.\\" + directory + ":";
cout<<"current directory is "<<path<<endl;
cout<<"Enter Options: \n1- dir \n2- type file_name.extention \n3- del file_name.extention\n\n";
again:
cin>>swich_value;

if(swich_value.at(1)!='i')
    cin>>file_name;
string answer;
switch(swich_value.at(1)){  
case 'i':
    dirFunction(directory);
    cout<<"\nare  you want to do another process: y or n?";
    cin>>answer;
    if (answer.at(0)=='y')
        goto again;
    break;
case 'y':
    typeFunction(removeExtention(file_name), directory);
    cout<<"\nare  you want to do another process: y or n?";
    cin>>answer;
    if (answer.at(0)=='y')
        goto again;
    break;
case 'e':
    delFunction(removeExtention(file_name), directory);
    cout<<"\nare  you want to do another process: y or n?";
    cin>>answer;
    if (answer.at(0)=='y')
        goto again;
    break;


}
}
于 2015-11-26T22:46:47.177 回答
1

您可以使用“boost::filesystem”

#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

unsigned long long int get_directory_size(const fs::path& directory){
    if (!fs::exists(directory)) return 0;

    if (fs::is_directory(directory)){
        unsigned long long int ret_size = 0;
        fs::directory_iterator m_dir_itr(directory);

        for (m_dir_itr = fs::begin(m_dir_itr); m_dir_itr != fs::end(m_dir_itr); ++m_dir_itr){
            fs::directory_entry m_dir_entry = *m_dir_itr;
            if (fs::is_regular_file(m_dir_entry.path())){
                ret_size += fs::file_size(m_dir_entry.path());
            }else if (fs::is_directory(m_dir_entry.path())){
                ret_size += get_directory_size(m_dir_entry.path());
            }
        }

        return ret_size;
    } else if (fs::is_regular_file(directory)){
        return fs::file_size(directory);
    }

    return 0;
}

#include <stdio.h>

int main(int /*argc*/, char** /*argv*/) {
    // Assuming 'C:/Folder' be any directory then its size can be found using
    auto folder_size = get_directory_size("C:/Folder");
    printf("Size of 'C:/Folder' is %d\n",folder_size);
    return 0;
}
于 2017-11-05T05:18:40.300 回答
1

随着 的引入std::filesystem,您不再需要使用任何系统 API 或任何外部库。

#include <filesystem>
namespace n_fs = ::std::filesystem;
double archive::getFolderSize(std::string path)
{
        double r = 0.0;
        try{
           if (!n_fs::is_directory(path))
           {
                r += (double)n_fs::file_size(path);
           }
           else
           {
                for(auto entry: n_fs::directory_iterator(path))
                getFolderSize(entry.path().string());
            }
        } 
        catch(exception& e)
        { 
            std::cout << e.what() << std::endl();
        }
        return r;
}

int main(){
    double folderSize = getFolderSize("~/dev/"); //Replace with your path
    std::cout << "Size of Folder: " << folderSize;
}
于 2019-04-27T11:49:24.127 回答
0

尝试使用 GetFileSizeEx 函数。以下是一些示例代码。不过,您需要从 LARGE_INTEGER 联合中获取大小。

#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <io.h>
using namespace std;
int main()
{
    FILE *fp;
    fp = fopen("C:\test.txt","r");
    int fileNo = _fileno(fp);
    HANDLE cLibHandle = (HANDLE)_get_osfhandle(fileNo);
    long int fileSize = 0;
    LARGE_INTEGER fileSizeL;
    GetFileSizeEx(cLibHandle, &fileSizeL);
    return 0;
}
于 2013-03-19T10:54:18.480 回答
0

5 年,而不是标准 C++ 的简单解决方案,这就是为什么我想为这个问题贡献我的解决方案:

uint64_t GetDirSize(const std::string &path)
{
    uint64_t size = 0;
    for (const auto & entry : std::experimental::filesystem::directory_iterator(path))
    {
        if(entry.status().type() == std::experimental::filesystem::file_type::regular)
            size += std::experimental::filesystem::file_size(entry.path());
        if (entry.status().type() == std::experimental::filesystem::file_type::directory)
            size += GetDirSize(entry.path().generic_string());
    }
    return size;
}

例如, GetDirSize("C:\\dir_name") 如果您使用的是 Windows,请通过调用来使用它。

于 2019-03-08T17:16:07.957 回答
0

在 Windows 上计算文件夹大小(以字节为单位)。

size_t GetFolderSizeInBytes(std::wstring path)
{
    size_t result = 0;
    WIN32_FIND_DATA findData;
    HANDLE hFileHandle;
    std::wstring sourcePath(path);

    if (GetFileAttributes(sourcePath.c_str()) & FILE_ATTRIBUTE_DIRECTORY)
        sourcePath.push_back(L'\\');

    std::wstring fileName(sourcePath);
    fileName.append(L"*");

    hFileHandle = FindFirstFileEx(
            fileName.data(),
            FindExInfoStandard,
            &findData,
            FindExSearchNameMatch,
            NULL,
            FIND_FIRST_EX_ON_DISK_ENTRIES_ONLY);

    if (hFileHandle != INVALID_HANDLE_VALUE)
    {
        do
        {
            if (!wcscmp(findData.cFileName, L".") || !wcscmp(findData.cFileName, L".."))
                continue;

            if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
            {
                // Folder
                std::wstring newPath = path + L"\\" + findData.cFileName;
                result += GetFolderSizeInBytes(newPath);
            }
            else
            {
                // File
                unsigned long high = findData.nFileSizeHigh;
                unsigned long low = findData.nFileSizeLow;
                size_t size = size_t(high * (MAXWORD + 1)) + low;
                result += size;
            }
        } while (FindNextFile(hFileHandle, &findData));

        FindClose(hFileHandle);
    }

    return result;
}
于 2021-07-15T21:28:47.883 回答