Размер каталога
Есть ли способ получить размер каталога/размер папки без фактического прохождения этого каталога и добавления в него каждого файла? В идеале хотелось бы использовать некоторую библиотеку, например boost, но win api тоже будет в порядке.
Ответы
Ответ 1
Насколько мне известно, вы должны сделать это с помощью итерации в большинстве операционных систем.
Вы можете взглянуть на boost.filesystem, эта библиотека имеет recursive_directory_iterator, она будет перебирать хотя бы файл в системе, получая накопление размера.
http://www.boost.org/doc/libs/1_49_0/libs/filesystem/v3/doc/reference.html#Class-recursive_directory_iterator
include <boost/filesystem.hpp>
int main()
{
namespace bf=boost::filesystem;
size_t size=0;
for(bf::recursive_directory_iterator it("path");
it!=bf::recursive_directory_iterator();
++it)
{
if(!bf::is_directory(*it))
size+=bf::file_size(*it);
}
}
PS: вы можете сделать это намного чище, используя std:: accumulate и lambda, я просто CBA
Ответ 2
Я не думаю, что есть что-то подобное, по крайней мере, нет функции win32 api.
Натурально для окон:
void DirectoryInfo::CalculateSize(std::string _path)
{
WIN32_FIND_DATAA data;
HANDLE sh = NULL;
sh = FindFirstFileA((_path+"\\*").c_str(), &data);
if (sh == INVALID_HANDLE_VALUE )
{
return;
}
do
{
// skip current and parent
if (std::string(data.cFileName).compare(".") != 0 && std::string(data.cFileName).compare("..") != 0)
{
// if found object is ...
if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
{
// directory, then search it recursievly
this->CalculateSize(_path+"\\"+data.cFileName);
} else
{
// otherwise get object size and add it to directory size
this->dirSize += (__int64) (data.nFileSizeHigh * (MAXDWORD ) + data.nFileSizeLow);
}
}
} while (FindNextFileA(sh, &data)); // do
FindClose(sh);
}
Ответ 3
Вы должны перемещать файлы. Получение правильного результата сложно, если в дереве есть жесткие ссылки или точки повторной обработки. Подробнее см. Raymond Chen сообщение в блоге.
Ответ 4
Zilog написал неплохой ответ, но я сделал бы это схожим, но другим способом.
У меня есть файл определения типов с помощью:
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 и возвращает неудачные dirs, если вы этого хотите.
Для вызова используйте:
StringVector vect;
CalculateDirSize(L"C:\\boost_1_52_0", &vect);
CalculateDirSize(L"C:\\boost_1_52_0");
Но никогда не проходите size