Как узнать размер файла qt

Обновлено: 02.07.2024

Как оказалось, узнать размер файла в языке C - совсем нетривиальная задача. В процессе её решения как минимум вы обязательно столкнетесь с переполнением целочисленного типа данных. В данной статье я приведу 4 способа получения размера файла с использованием функций из стандартной библиотеки C, функций из библиотеки POSIX и функций из библиотек Windows.
Способ 1: решение "в лоб" (скомпилируется везде, но работает очень долго)
Мы просто откроем файл в бинарном режиме и в цикле считаем из него байт за байтом.

Очевидным недостатком способа является скорость работы. Если у нас файл будет на много гигабайт, то только размер файла будет считаться относительно долго (это сколько байт то надо считать?), а надо же еще остальную программу выполнять.
Достоинство такого способа - работать должен на любой платформе. Ну и конечно можно ускорить процесс за счет считывания бОльшего количества байт.

Способ 2: с использованием функций fseek и ftell (ограничен для объемных файлов и работает не всегда верно)

Данный способ основан на использовании функций стандартной библиотеки C: fseek и ftell. Что происходит - открываем файл в бинарном режиме, перемещаем внутренний указатель положения в файле сразу в конец с помощью fseek, получаем номер последнего байта с помощью ftell.

Проблем у данного способа несколько.
Первое - это возвращаемый тип функции ftell. У разных компиляторов на разных платформах по разному. Если у вас 32х битная система, то данный способ будет работать только для файлов, размером меньше 2048 Мб, поскольку максимальное значение для возвращаемого функцией типа long там будет 2147483647. На системах с большей разрядностью будет работать лучше, из-за большего значения максимума для long. Но подобная нестабильность будет мешать. Хотя у меня на 64х битой системе на компиляторе gcc данный способ для файлов больше 8 Гб выводил некорректные значения.
Второе - гарантированность работы fseek и ftell. Коротко говоря, на разных платформах работает по-разному. Где то будет точно возвращать значение положения последнего байта, где то будет возвращать неверное значение. То есть точность данного способа негарантированна.

Плюсом является то, что эти функции из стандартной библиотеки - скомпилируется почти везде.

Стоит сказать, что хитрые инженеры из Microsoft придумали функции _fseeki64 и _ftelli64, которые, как понятно из их названия, работают с int64, что решает проблему с размером файла в MSVC под Windows.

Способ 3: (под Linux (POSIX))

Данный способ основан на использовании системном вызове fstat с использованием специальной структуры struct stat. Как работает: открываем файл через open() или fopen(), вызываем fstat для дескриптора файла (если открыли через fopen, то в fstat надо положить результат fileno от указателя потока FILE), указав на буферную структуру для результатов, и получаем значения поля буферной структуры st_size.

На этом шаге рассмотрим возможность просмотра информации о файле с помощью класса QFileInfo.

Иногда необходимо убедиться, что исследуемый объект является каталогом, а не файлом, и наоборот. Для этой цели существуют методы isFile() и isDir().

Если объект является файлом, метод isFile() возвращает значение true, иначе — false. Если объект является каталогом, то метод isDir() возвращает значение true, иначе — false.

Кроме этих методов, класс QFileInfo содержит метод isSymLink(), возвращающий значение true, если объект является символьной ссылкой (термин "symbolic link" применяется в UNIX, в ОС Windows принято название ярлык (shortcut)).

Путь и имя файла

Чтобы получить абсолютный путь к файлу, нужно воспользоваться методом absoluteFilePath(), а для получения относительного пути следует использовать метод filePath(). Для получения имени файла нужно вызвать метод fileName(), который возвращает имя файла вместе с его расширением. Если нужно только имя файла, то следует вызвать метод baseName(). Для получения расширения используется метод completeSuffix().

Информация о дате и времени

Иногда нужно узнать время создания файла, время его последнего изменения или чтения. Для этого класс QFileInfo предоставляет методы created(), lastModified() и lastRead() соответственно. Эти методы возвращают объекты класса QDateTime, которые можно преобразовать в строку методом toString(). Например:

Получение атрибутов файла

Атрибуты файла дают информацию о том, какие операции можно проводить с файлом. Для их получения в классе QFileInfo существуют следующие методы:

  • isReadable() — возвращает значение true, если из указанного файла можно читать информацию;
  • isWriteable() — возвращает значение true, если в указанный файл можно записывать информацию;
  • isHidden() — возвращает значение true, если указанный файл является скрытым;
  • isExecutable() — возвращает значение true, если указанный файл можно исполнять. В ОС UNIX это определяется не на основании расширения файла, как принято в DOS и ОС Windows, а из свойств самого файла.

Определение размера файла

Метод size() класса QFileInfo возвращает размер файла в байтах. Размер файлов редко отображается в байтах, чаще используются специальные буквенные обозначения, сообщающие об его размере. Например, для килобайта — это буква K, для мегабайта — M, для гигабайта — G, а для терабайта — T. Следующая функция позволяет сопровождать буквенными обозначениями размеры, лежащие даже в терабайтном диапазоне:

Наблюдение за файлами и каталогами

Поскольку файлы и каталоги используются не только вашей программой, бывает очень полезно получать уведомления в случае их изменений. Например, вы написали файловый браузер и показываете содержимое текущего каталога. Но пользователь может воспользоваться другими программами и скопировать новые файлы в этот каталог, после чего ото-ражаемая информация перестанет отвечать действительности. Не имея специального механизма слежения за изменением текущего каталога, вы не сможете узнать о необходимости обновить его содержимое.

Класс QDir дает возможность навигации по файловой системе и получать информацию о файлах, независимо от типа операционной системы. Чтобы показать некоторые особенности класса QDir, напишем небольшое консольное приложение, которое подсчитывает суммарный объем всех файлов с изображениями в заданном каталоге и вложенных подкаталогах.

Основу приложения составляет функция imageSpace(), которая суммирует размеры файлов в заданном каталоге:

Затем, в цикле, осуществляется проход по списку файлов и суммируются их размеры. Класс QFileInfo позволяет получить доступ к таким характеристикам файла, как размер, права доступа, владелец и время (создания, последнего обращения, последнего изменения).

Вторым обращением к entryList() создается список вложенных подкаталогов. После чего, в цикле, выполняется проход по подкаталогам, с рекурсивным вызовом imageSpace() для каждого из них.

Полный путь к вложенным подкаталогам "собирается" из полного пути к текущему каталогу, символа слэша и имени подкаталога (*it). Класс QDir интерпретирует символ "/" как разделитель имен каталогов независимо от используемой операционной системы. Перед выводом полного пути перед пользователем, можно вызвать функцию QDir::convertSeparators(), которая преобразует символ "/" в корректное представление, в зависимости от используемой платформы.

Добавим в нашу программу функцию main():

Для начальной инициализации переменной path была использована функция QDir::currentDirPath(), которая возвращает полное имя текущего каталога. В качестве альтернативы можно было бы использовать функцию QDir::homeDirPath(), возвращающую полный путь к домашнему каталогу пользователя. Если путь к каталогу задается пользователем из командной строки, то он замещает значение по-умолчанию. В заключение вызывается функция imageSpace(), которая подсчитывает суммарный размер всех файлов с изображениями.

Класс QDir предоставляет ряд других функций, для работы с каталогами и файлами, среди них: rename(), exists(), mkdir() и rmdir().

Редко встречается приложение, которое не обращается к файлам. Работа с директориями (папками, в терминологии ОС Windows) и файлами — это та область, в которой не все операции являются платформонезависимыми,

поэтому Qt предоставляет свою собственную поддержку этих операций, состоящую из следующих классов:

QDir — для работы с директориями;

QFile — для работы с файлами;

QFileInfо — для получения файловой информации;

QIODevice — абстрактный класс для ввода/вывода;

QBuffer — для эмуляции файлов в памяти компьютера.

Ввод/вывод. Класс QIODevice

QIODevice — это абстрактный класс, обобщающий устройство ввода/вывода, который содержит виртуальные методы для открытия и закрытия устройства ввода/вывода, а также для чтения и записи блоков данных или отдельных символов.

Реализация конкретного устройства происходит в унаследованных классах.

В Qt есть четыре класса, наследующие класс QIODevice :

QFile — класс для проведения операций с файлами;

QBuffer — позволяет записывать и считывать данные в массив QByteArray , как будто бы это устройство или файл;

QAbstractSocket — базовый класс для сетевой коммуникации посредством сокетов.

QProcess — этот класс предоставляет возможность запуска процессов с дополнительными аргументами и позволяет обмениваться информацией с этими процессами посредством методов, определенных в QIODevice .

Для работы с устройством его необходимо открыть в одном из режимов, определенных В заголовочном файле класса QIODevice :

QIODevice::NotOpen — устройство не открыто (это значение не имеет смысла передавать в метод open() );

QIODevice::ReadOnly — открытие устройства только для чтения данных;

QIODevice::writeOnly — открытие устройства только для записи данных;

QIODevice::ReadWrite — открытие устройства для чтения и записи данных (то же, что и IO_ReadOnly | IO_WriteOnly );

QIODevice::Append — открытие устройства для добавления данных;

QIODevice::Unbuffered — открытие для непосредственного доступа к данным, в обход промежуточных буферов чтения и записи;

QIODevice::Text — применяются преобразования символов переноса строки в зависимости от платформы. Для ОС Windows, например — \r\n, а для MacOS X и

QIODevice::Truncate — все данные устройства, по возможности, должны быть удалены при открытии.

Для того чтобы в любой момент времени исполнения программы узнать, в каком из режимов было открыто устройство, нужно вызвать метод openMode() .

Считывать и записывать данные можно с помощью

методов read() и write() соответственно. Для чтения всех данных сразу определен

метод readAll() , который возвращает их в объекте типа QByteArray . Строку или символ можно прочитать методами readLine() и getChar() соответственно.

В классе QIODevice определен метод для смены текущего положения seek() . Получить текущее положение можно вызовом метода pos() . Но не забывайте, что эти методы применимы только для прямого доступа к данным. При последовательном доступе, каким является сетевое соединение, они теряют смысл. Более того, в этом случае теряет смысл и метод size() , возвращающий размер данных устройства. Все эти операции применимы только

для QFile , QBuffer и QTemporaryFile .

Для создания собственного класса устройства ввода/вывода, для которого Qt не

предоставляет поддержки, необходимо унаследовать класс QIODevice и реализовать в нем методы readData() и writeData() . В большинстве случаев может потребоваться перезаписать методы open() , close() и atEnd() .

Благодаря интерфейсу класса QIODevice можно работать со всеми устройствами одинаково, при этом не имеет значения, является ли устройство файлом, буфером или другим устройством. Выведем на консоль данные из любого устройства.

void print(QIODevice *pdev)

char ch; QString str;

pdev->open(QIODevice::ReadOnly); for (; !pdev->atEnd();)

pdev->getChar(&ch); str += ch;

Класс QIODevice предоставляет ряд методов, с помощью которых можно получить информацию об устройстве ввода/вывода. Например, одни устройства могут только записывать информацию, другие — только считывать, а третьи способны делать и то, и другое. Чтобы узнать об этом, следует воспользоваться

методами isReadable() и isWriteable() .

Класс QFile унаследован от класса QIODevice . В нем содержатся методы для работы с файлами: открытия, закрытия, чтения и записи данных. Создать объект можно, передав в конструкторе строку, содержащую имя файла. Можно ничего не

передавать в конструкторе, а сделать это после создания объекта, вызовом метода setName() . Например:

В процессе работы с файлами иногда требуется узнать, открыт файл или нет. Для этого вызывается метод QIODevice::isOpen() , который вернет true , в том случае,

если файл открыт, иначе — false . Чтобы закрыть файл, нужно вызвать метод close() . С закрытием произведется запись всех данных буфера. Если

требуется произвести запись данных буфера в файл без его закрытия, то вызывается метод QFile::flush() .

Проверить, существует ли нужный вам файл, можно статическим

методом QFile::exists() . Этот метод принимает строку, содержащую полный или относительный путь к файлу. Если файл найден, то метод возвратит true , в противном случае — false . Для проведения этой операции существует и нестатический метод QFile::exists() .

Методы QIODevice::read() и QIODevice::write() позволяют считывать и записывать файлы блоками.

Продемонстрируем применение некоторых методов работы с файлами:

QFile file1( "file1.dat" );

QFile file2( "file2.dat" );

//Файл уже существует. Перезаписать?

qDebug() << "Ошибка открытия для чтения" ;

qDebug() << "Ошибка открытия для записи" ;

char a [1024]; while (!file1.atEnd())

int nBlocksize = file1.read(a, sizeof (a)); file2.write(a, nBlocksize);

Если требуется считать или записать данные за один раз, то используют методы QIODevice::write() и QIODevice::readAll() . Все данные можно считать в объект класса QByteArray , а потом записать из него в другой файл:

QFile file1( "file1.dat" );

QFile file2( "file2.dat" );

//Файл уже существует. Перезаписать?

qDebug() << "Ошибка открытия для чтения" ;

qDebug() << "Ошибка открытия для записи" ;

QByteArray a = file1.readAll(); file2.write(a);

Операция считывания всех данных сразу, в зависимости от размера файла, может занять много оперативной памяти, а значит, к этому следует прибегать только в случаях острой необходимости или в том случае, когда файлы занимают мало места. Расход памяти при считывании сразу всего файла можно значительно сократить при том условии, что файл содержит избыточную информацию. Тогда можно воспользоваться функциями сжатия qCompress() и qUncompress() , которые определены вместе с классом QByteArray . Эти функции получают, в качестве аргумента, объект класса QByteArray и возвращают, в качестве результата, новый объект класса QByteArray .

Для удаления файла класс QFile содержит статический метод remove() . В этот метод необходимо передать строку, содержащую полный или относительный путь удаляемого файла.

Класс QBuffer унаследован от QIODevice , и представляет собой эмуляцию файлов в памяти компьютера (memory mapped files). Это позволяет записывать информацию в оперативную память и использовать объекты как обычные файлы (открывать при помощи метода open() и закрывать методом close() ). При помощи методов write() и read() можно считывать и записывать блоки данных. Можно это так же сделать при помощи потоков, которые будут рассмотрены далее. Рассмотрим пример использования класса QBuffer:

out << QString( "Message" );

Как видно из этого примера, сами данные сохраняются внутри объекта

класса QByteArray . При помощи метода buffer() можно получить константную ссылку к внутреннему объекту QByteArray , а при помощи

метода setBuffer() можно устанавливать другой объект QByteArray для его использования в качестве внутреннего.

Класс QBuffer полезен для проведения операций кэширования. Например, можно считывать файлы растровых изображений в объекты класса QBuffer , а затем, по необходимости, получать данные из них.

Иногда приложению может потребоваться создать временный файл. Это может быть связано, например, с промежуточным хранением большого объема данных или передачей этих данных какой-либо другой программе.

Класс QTemporaryFile представляет реализацию для временных файлов. Этот класс самостоятельно создает себе имя с гарантией его уникальности, для того чтобы не возникало конфликтов, в результате которых могли бы пострадать уже существующие файлы. Сам файл будет расположен в каталоге для промежуточных данных, местонахождение которого можно получить вызовом

метода QDir :: tempPath (). С уничтожением объекта будет уничтожен и сам временный файл.

Разные платформы имеют разные способы представления путей. ОС Windows содержит буквы дисков, например: C:\Windows\System. UNIX использует root, например: /usr/bin. Обратите внимание, что для разделения имен директорий в обоих представлениях используются разные знаки. Для представления директорий в платформонезависимой форме Qt предоставляет класс QDir .

Для этих целей класс предоставляет целый ряд статических методов:

QDir :: current () — возвращает путь директории приложения;

QDir :: root () — возвращает root-директорию;

QDir :: drives ()—возвращает указатель на список объектов класса

QFileinfo с узловыми директориями (root). Для Windows это будут С:\, D:\ и т.

QDir :: home () — возвращает персональную директорию пользователя.

Класс QDir не предоставляет методов для определения текущего каталога приложения. Но если вам потребуется определить, из какого каталога было запущенно приложение, то следует воспользоваться

методом QApplication :: applicationDirPath (), либо QApplication :: applicationFilePath (),

возвращающим, в добавок ко всему, и имя приложения.

Существование директории можно проверить с помощью метода exists (). Чтобы перемещаться по директориям, можно использовать метод cd (), который принимает, в качестве параметра, абсолютный путь директории, и cdUp (). Вызов cd ("..") эквивалентен вызову метода cdUp ().

Для конвертирования относительного пути директории в абсолютный можно вызвать метод makeAbsolute ().

Для создания директории нужно вызвать метод mkdir (). В случае успешного проведения этой операции метод вернет значение true , в случае неудачи — false .

Если вам потребуется переименовать директорию, то воспользуйтесь методом rename (). В этот метод первым параметром нужно передать старый путь, а вторым — новый. Если операция будет проведена успешно, то метод вернет true , иначе — false .

Удаление директорий производится методом rmdir (), который получает путь, и в случае успеха возвращает true , а в случае неудачи — false .

При помощи класса QDir можно получить содержимое указанной директории. При этом допускается применять различные фильтры, чтобы исключить из списка не интересующие вас файлы. Для этих целей в классе определены методы entryList () и entryInfoList (). Первый возвращает список имен элементов ( QStringList ), а второй — информационный список ( QFileInfoList ). Если вам нужно узнать только количество элементов, находящихся в директории, то просто вызовите

Программа, показанная на рисунке, осуществляет рекурсивный поиск файлов в директории, указанной в текстовом поле Directory (Директория). Нажатие кнопки с растровым изображением откроет диалоговое окно выбора нужной директории. В текстовом поле Mask (Маска) задается фильтр для отображаемых файлов. Например, для отображения исходных файлов на языке C++ нужно задать в поле Mask (Маска) *. срр и *. h . После нажатия кнопки Find (Поиск) производится отображение файлов, в соответствии с заданными параметрами. Результаты отображаются в виджете многострочного текстового поля.

FileFinder::FileFinder(QWidget* pwgt/*= 0*/) : QWidget(pwgt)

= new QLineEdit( "*.cpp *.h" );

new QLabel( "&Directory" );

new QLabel( "&Mask" );

new QPushButton( "&Find" );

connect(pcmdDir, SIGNAL (clicked()), SLOT (slotBrowse())); connect(pcmdFind, SIGNAL (clicked()), SLOT (slotFind()));

QGridLayout* pgrdLayout = new QGridLayout; pgrdLayout->setMargin(5); pgrdLayout->setSpacing(15); pgrdLayout->addWidget(plblDir, 0, 0); pgrdLayout->addWidget(plblMask, 1, 0); pgrdLayout->addWidget(m_ptxtDir, 0, 1); pgrdLayout->addWidget(m_ptxtMask, 1, 1); pgrdLayout->addWidget(pcmdDir, 0, 2); pgrdLayout->addWidget(pcmdFind, 1, 2); pgrdLayout->addWidget(m_ptxtResult, 2, 0, 1, 3); setLayout(pgrdLayout);

В конструкторе класса FileFinder создаются виджеты однострочного и многострочного текстовых полей

(указатели m _ ptxtDir , m _ ptxtMask и m _ ptxtResult ). Первый виджет инициализируется абсолютным путем, возвращаемым методом QDir :: absolutePath (), который, в свою очередь, инициализируется значением текущей директории, возвращаемой методом QDir :: current () . Второй виджет инициализируется строкой, предназначенной для фильтрации найденных файлов. Для старта операции поиска и открытия диалогового окна выбора директории создаются две кнопки нажатия— указатели pcmdFind и pcmdDir , которые соединяются со слотами slotFind () и slotBrowse(). В конструкторе создаются два виджета надписей, а с помощью метода setBuddy () они ассоциируются с виджетами однострочных текстовых полей. Созданные виджеты размещаются в виде таблицы при помощи объекта класса QGridLayout .

QString str = QFileDialog::getExistingDirectory

"Select a Directory" ,

Метод slotBrowse (), который открывает диалоговое окно для выбора директории поиска. После закрытия этого окна директория записывается в текстовое поле Directory (Директория) с помощью метода setText ().

Метод slotFind () запускает операцию поиска и передает в метод start () выбранную пользователем директорию.

void FileFinder::start( const QDir& dir)

QStringList listFiles = dir.entryList(m_ptxtMask->text().split( " " ), QDir::Files);

QStringList listDir = dir.entryList(QDir::Dirs); foreach (QString subdir, listDir)

Процесс поиска заданных файлов может быть длительным, что может привести к "замиранию" графического интерфейса программы. Поэтому, для подавления этого нежелательного эффекта, при каждом вызове метода воспользуемся методом QApplication :: processEvent () и дадим возможность обработаться накопившимся событиям. В методе start о переменная listFiles получает список файлов текущей директории. Для этого в методе установлены два параметра. Первый представляет собой список шаблонов поиска, которые распространяются на имена и расширения файлов. В нашем случае мы преобразуем строку в список, разделив ее посредством пробелов, с помощью QString :: split (). Второй параметр ( QDir :: Files ) указывает на то, что список должен содержать только файлы. Элементы полученного списка добавляются в виджет многострочного текстового поля с помощью метода append (). По завершению работы цикла добавления, в метод entryList () передается параметр QDir :: Dirs для получения списка директорий. Для каждого из элементов списка, кроме "." и "..", вызывается метод start ().

Задача этого класса состоит в предоставлении информации о свойствах файла, например: имя, размер, время последнего изменения, права доступа и т. д. Объект класса QFileInfo создается передачей в его конструктор пути к файлу, но можно передавать и объекты класса QFile .

Файл или каталог?

Иногда необходимо убедиться, что исследуемый объект является каталогом, а не файлом и наоборот. Для этой цели существуют методы isFile () и isDir ().

В том случае, если объект является файлом, метод isFile () возвращает значение булевого типа true , иначе — false . Если объект является директорией, то метод isDir () возвращает true , иначе — false . Кроме этих методов,

класс QFileInfo содержит метод isSymLink (), возвращающий true , если объект является символьной ссылкой (symbolic link или shortcut в ОС Windows).

Символьные ссылки применяются в UNIX для обеспечения связи с файлами или каталогами. Создаются они при помощи команды "ln" с ключом "-s".

Путь и имя файла в Qt

Чтобы получить путь к файлу, нужно воспользоваться методом absoluteFilePath (). Для получения относительного пути к файлу следует использовать метод filePath (). Для получения имени файла нужно вызвать метод fileName (), который возвращает имя файла вместе с его расширением. Если нужно только имя файла, то следует вызвать метод baseName (). Для получения расширения используется

Информация о дате и времени файла в Qt

Иногда нужно узнать время создания файла, время его последнего изменения или чтения. Для этого класс QFileInfo предоставляет методы created (), lastModified () и lastRead () соответственно. Эти методы возвращают объекты класса QDateTime , которые можно преобразовать в строку методом toString (). Например:

//Дата и время создания файла fileInfo.created().toString();

//Дата и время последнего изменения файла fileInfo.lastModified().toString();

//Дата и время последнего чтения файла

Получение атрибутов файла в Qt

Атрибуты файла дают информацию о том, какие операции можно проводить с файлом.

Для их получения в классе QFileInfо существуют следующие методы:

isReadable () —возвращает true , если из указанного файла можно читать информацию;

isWriteable () —возвращает true , если в указанный файл можно записывать информацию;

isHidden () — возвращает true , если указанный файл является скрытым;

isExecutable () —возвращает true , если указанный файл можно исполнять. В ОС UNIX это определяется не на основании расширения файла, как привыкли считать программисты в DOS и ОС Windows, а посредством свойств самого файла.

Определение размера файла в Qt

Метод size () класса QFileInf о возвращает размер файла в байтах. Размер файлов редко отображается в байтах, чаще используются специальные буквенные обозначения, сообщающие об его размере. Например, для килобайта — это буква К, для мегабайта — М, для гигабайта — G, а для терабайта — Т. Следующая функция позволяет сопровождать буквенными обозначениями размеры, лежащие даже в терабайтном диапазоне (вполне возможно, что через несколько лет это будет обычный размер файла):

QString fileSize(qint64 nSize)

for (; nSize > 1023; nSize /= 1024, ++i) < >return QString().setNum(nSize) + "BKMGT" [i];

Объекты файлов, сами по себе, обладают только элементарными методами для чтения и записи информации. Использование потоков делает запись и считывание файлов более простым и гибким. Для файлов, содержащих текстовую информацию, следует использовать класс QTextStream , а для двоичных файлов —

Применение классов QTextStream и QDataStream такое же, как и для стандартного потока в языке C++ ( iostream ), с той лишь разницей, что они могут работать с объектами класса QIODevice . Благодаря этому, потоки можно использовать и для своих собственных классов, унаследованных от QIODevice .

Для записи данных в поток используется оператор <<, а для чтения данных из потока — >>.

Читайте также: